GenI 0.20.2 → 0.22
raw patch · 86 files changed
+10501/−13047 lines, 86 filesdep +GenIdep +MaybeTdep +bytestringdep −paralleldep −test-framework-quickcheckdep −uniplatedep ~QuickCheckdep ~basedep ~binarysetup-changedPVP ok
version bump matches the API change (PVP)
Dependencies added: GenI, MaybeT, bytestring, cabal-macosx, deepseq, hslogger, old-locale, ordered, smallcheck, syb, test-framework-quickcheck2, test-framework-smallcheck, text, time, yaml-light
Dependencies removed: parallel, test-framework-quickcheck, uniplate, wx
Dependency ranges changed: QuickCheck, base, binary, filepath, json, mtl, parsec, split, test-framework, utf8-string
API changes (from Hackage documentation)
- NLP.GenI.Btypes: Auxiliar :: Ptype
- NLP.GenI.Btypes: AvPair :: String -> GeniVal -> AvPair
- NLP.GenI.Btypes: Foot :: GType
- NLP.GenI.Btypes: GAnon :: GeniVal
- NLP.GenI.Btypes: GConst :: [String] -> GeniVal
- NLP.GenI.Btypes: GN :: NodeName -> Flist -> Flist -> Bool -> [String] -> GType -> Bool -> String -> GNode
- NLP.GenI.Btypes: GVar :: String -> GeniVal
- NLP.GenI.Btypes: ILE :: [String] -> String -> [GeniVal] -> Flist -> Flist -> Flist -> Ptype -> Sem -> [SemPols] -> ILexEntry
- NLP.GenI.Btypes: Initial :: Ptype
- NLP.GenI.Btypes: Lex :: GType
- NLP.GenI.Btypes: Other :: GType
- NLP.GenI.Btypes: Subs :: GType
- NLP.GenI.Btypes: TT :: [GeniVal] -> String -> String -> Flist -> Ptype -> Maybe Sem -> [String] -> Tree a -> Ttree a
- NLP.GenI.Btypes: TestCase :: String -> String -> SemInput -> [String] -> [(String, Map (String, String) [String])] -> TestCase
- NLP.GenI.Btypes: Unspecified :: Ptype
- NLP.GenI.Btypes: alphaConvert :: (Collectable a, DescendGeniVal a) => String -> a -> a
- NLP.GenI.Btypes: alphaConvertById :: (Collectable a, DescendGeniVal a, Idable a) => a -> a
- NLP.GenI.Btypes: avAtt :: AvPair -> String
- NLP.GenI.Btypes: avVal :: AvPair -> GeniVal
- NLP.GenI.Btypes: class Collectable a
- NLP.GenI.Btypes: class DescendGeniVal a
- NLP.GenI.Btypes: class Idable a
- NLP.GenI.Btypes: collect :: (Collectable a) => a -> Set String -> Set String
- NLP.GenI.Btypes: data AvPair
- NLP.GenI.Btypes: data GNode
- NLP.GenI.Btypes: data GType
- NLP.GenI.Btypes: data GeniVal
- NLP.GenI.Btypes: data ILexEntry
- NLP.GenI.Btypes: data Ptype
- NLP.GenI.Btypes: data TestCase
- NLP.GenI.Btypes: data Ttree a
- NLP.GenI.Btypes: descendGeniVal :: (DescendGeniVal a) => (GeniVal -> GeniVal) -> a -> a
- NLP.GenI.Btypes: emptyGNode :: GNode
- NLP.GenI.Btypes: emptyLE :: ILexEntry
- NLP.GenI.Btypes: emptyMacro :: MTtree
- NLP.GenI.Btypes: emptyPred :: Pred
- NLP.GenI.Btypes: foot :: Tree GNode -> GNode
- NLP.GenI.Btypes: fromGConst :: GeniVal -> [String]
- NLP.GenI.Btypes: fromGVar :: GeniVal -> String
- NLP.GenI.Btypes: gCategory :: Flist -> Maybe GeniVal
- NLP.GenI.Btypes: gaconstr :: GNode -> Bool
- NLP.GenI.Btypes: ganchor :: GNode -> Bool
- NLP.GenI.Btypes: gdown :: GNode -> Flist
- NLP.GenI.Btypes: glexeme :: GNode -> [String]
- NLP.GenI.Btypes: gnname :: GNode -> NodeName
- NLP.GenI.Btypes: gnnameIs :: NodeName -> GNode -> Bool
- NLP.GenI.Btypes: gorigin :: GNode -> String
- NLP.GenI.Btypes: gtype :: GNode -> GType
- NLP.GenI.Btypes: gup :: GNode -> Flist
- NLP.GenI.Btypes: idOf :: (Idable a) => a -> Integer
- NLP.GenI.Btypes: iequations :: ILexEntry -> Flist
- NLP.GenI.Btypes: ifamname :: ILexEntry -> String
- NLP.GenI.Btypes: ifilters :: ILexEntry -> Flist
- NLP.GenI.Btypes: iinterface :: ILexEntry -> Flist
- NLP.GenI.Btypes: instance [overlap ok] (Collectable a) => Collectable (Maybe a)
- NLP.GenI.Btypes: instance [overlap ok] (Collectable a) => Collectable (Tree a)
- NLP.GenI.Btypes: instance [overlap ok] (Collectable a) => Collectable (Ttree a)
- NLP.GenI.Btypes: instance [overlap ok] (Collectable a) => Collectable [a]
- NLP.GenI.Btypes: instance [overlap ok] (Collectable a, Collectable b, Collectable c) => Collectable (a, b, c)
- NLP.GenI.Btypes: instance [overlap ok] (Data a) => Data (Ttree a)
- NLP.GenI.Btypes: instance [overlap ok] (DescendGeniVal a) => DescendGeniVal (Map k a)
- NLP.GenI.Btypes: instance [overlap ok] (DescendGeniVal a) => DescendGeniVal (String, a)
- NLP.GenI.Btypes: instance [overlap ok] (Show a) => Show (Ttree a)
- NLP.GenI.Btypes: instance [overlap ok] Biplate (Maybe Sem) GeniVal
- NLP.GenI.Btypes: instance [overlap ok] Biplate (Tree GNode) GeniVal
- NLP.GenI.Btypes: instance [overlap ok] Biplate (Ttree GNode) GeniVal
- NLP.GenI.Btypes: instance [overlap ok] Biplate (Ttree String) GeniVal
- NLP.GenI.Btypes: instance [overlap ok] Biplate AvPair GeniVal
- NLP.GenI.Btypes: instance [overlap ok] Biplate GNode GeniVal
- NLP.GenI.Btypes: instance [overlap ok] Biplate ILexEntry GeniVal
- NLP.GenI.Btypes: instance [overlap ok] Biplate Pred GeniVal
- NLP.GenI.Btypes: instance [overlap ok] Collectable AvPair
- NLP.GenI.Btypes: instance [overlap ok] Collectable GNode
- NLP.GenI.Btypes: instance [overlap ok] Collectable GeniVal
- NLP.GenI.Btypes: instance [overlap ok] Collectable ILexEntry
- NLP.GenI.Btypes: instance [overlap ok] Data AvPair
- NLP.GenI.Btypes: instance [overlap ok] Data GNode
- NLP.GenI.Btypes: instance [overlap ok] Data GType
- NLP.GenI.Btypes: instance [overlap ok] Data ILexEntry
- NLP.GenI.Btypes: instance [overlap ok] Data Ptype
- NLP.GenI.Btypes: instance [overlap ok] DescendGeniVal (Ttree GNode)
- NLP.GenI.Btypes: instance [overlap ok] DescendGeniVal ([String], Flist)
- NLP.GenI.Btypes: instance [overlap ok] DescendGeniVal AvPair
- NLP.GenI.Btypes: instance [overlap ok] DescendGeniVal GNode
- NLP.GenI.Btypes: instance [overlap ok] DescendGeniVal ILexEntry
- NLP.GenI.Btypes: instance [overlap ok] DescendGeniVal Pred
- NLP.GenI.Btypes: instance [overlap ok] Eq AvPair
- NLP.GenI.Btypes: instance [overlap ok] Eq GNode
- NLP.GenI.Btypes: instance [overlap ok] Eq GType
- NLP.GenI.Btypes: instance [overlap ok] Eq ILexEntry
- NLP.GenI.Btypes: instance [overlap ok] Eq Ptype
- NLP.GenI.Btypes: instance [overlap ok] Ord AvPair
- NLP.GenI.Btypes: instance [overlap ok] Show AvPair
- NLP.GenI.Btypes: instance [overlap ok] Show GNode
- NLP.GenI.Btypes: instance [overlap ok] Show GType
- NLP.GenI.Btypes: instance [overlap ok] Show ILexEntry
- NLP.GenI.Btypes: instance [overlap ok] Show Ptype
- NLP.GenI.Btypes: instance [overlap ok] Show TestCase
- NLP.GenI.Btypes: instance [overlap ok] Typeable AvPair
- NLP.GenI.Btypes: instance [overlap ok] Typeable GNode
- NLP.GenI.Btypes: instance [overlap ok] Typeable GType
- NLP.GenI.Btypes: instance [overlap ok] Typeable ILexEntry
- NLP.GenI.Btypes: instance [overlap ok] Typeable Ptype
- NLP.GenI.Btypes: instance [overlap ok] Typeable1 Ttree
- NLP.GenI.Btypes: iparams :: ILexEntry -> [GeniVal]
- NLP.GenI.Btypes: iptype :: ILexEntry -> Ptype
- NLP.GenI.Btypes: isAnon :: GeniVal -> Bool
- NLP.GenI.Btypes: isConst :: GeniVal -> Bool
- NLP.GenI.Btypes: isVar :: GeniVal -> Bool
- NLP.GenI.Btypes: isemantics :: ILexEntry -> Sem
- NLP.GenI.Btypes: isempols :: ILexEntry -> [SemPols]
- NLP.GenI.Btypes: iword :: ILexEntry -> [String]
- NLP.GenI.Btypes: lexemeAttributes :: [String]
- NLP.GenI.Btypes: mergeSubst :: Subst -> Subst -> Subst
- NLP.GenI.Btypes: params :: Ttree a -> [GeniVal]
- NLP.GenI.Btypes: pfamily :: Ttree a -> String
- NLP.GenI.Btypes: pidname :: Ttree a -> String
- NLP.GenI.Btypes: pinterface :: Ttree a -> Flist
- NLP.GenI.Btypes: plugTree :: Tree NodeName -> NodeName -> Tree NodeName -> Tree NodeName
- NLP.GenI.Btypes: psemantics :: Ttree a -> Maybe Sem
- NLP.GenI.Btypes: ptrace :: Ttree a -> [String]
- NLP.GenI.Btypes: ptype :: Ttree a -> Ptype
- NLP.GenI.Btypes: replace :: (DescendGeniVal a) => Subst -> a -> a
- NLP.GenI.Btypes: replaceList :: (DescendGeniVal a) => [(String, GeniVal)] -> a -> a
- NLP.GenI.Btypes: root :: Tree a -> a
- NLP.GenI.Btypes: rootUpd :: Tree a -> a -> Tree a
- NLP.GenI.Btypes: setAnchor :: [String] -> Tree GNode -> Tree GNode
- NLP.GenI.Btypes: setLexeme :: [String] -> Tree GNode -> Tree GNode
- NLP.GenI.Btypes: showAv :: AvPair -> String
- NLP.GenI.Btypes: showFlist :: Flist -> String
- NLP.GenI.Btypes: showLexeme :: [String] -> String
- NLP.GenI.Btypes: showPairs :: Flist -> String
- NLP.GenI.Btypes: showPred :: Pred -> String
- NLP.GenI.Btypes: showSem :: Sem -> String
- NLP.GenI.Btypes: sortFlist :: Flist -> Flist
- NLP.GenI.Btypes: sortSem :: Sem -> Sem
- NLP.GenI.Btypes: spliceTree :: NodeName -> Tree NodeName -> NodeName -> Tree NodeName -> Tree NodeName
- NLP.GenI.Btypes: subsumeSem :: Sem -> Sem -> [(Sem, Subst)]
- NLP.GenI.Btypes: tcExpected :: TestCase -> [String]
- NLP.GenI.Btypes: tcName :: TestCase -> String
- NLP.GenI.Btypes: tcOutputs :: TestCase -> [(String, Map (String, String) [String])]
- NLP.GenI.Btypes: tcSem :: TestCase -> SemInput
- NLP.GenI.Btypes: tcSemString :: TestCase -> String
- NLP.GenI.Btypes: toKeys :: Sem -> [String]
- NLP.GenI.Btypes: tree :: Ttree a -> Tree a
- NLP.GenI.Btypes: type Flist = [AvPair]
- NLP.GenI.Btypes: type Lexicon = Map String [ILexEntry]
- NLP.GenI.Btypes: type LitConstr = (Pred, [String])
- NLP.GenI.Btypes: type MTtree = Ttree GNode
- NLP.GenI.Btypes: type Macros = [MTtree]
- NLP.GenI.Btypes: type MorphLexEntry = (String, String, Flist)
- NLP.GenI.Btypes: type NodeName = String
- NLP.GenI.Btypes: type Pred = (GeniVal, GeniVal, [GeniVal])
- NLP.GenI.Btypes: type Sem = [Pred]
- NLP.GenI.Btypes: type SemInput = (Sem, Flist, [LitConstr])
- NLP.GenI.Btypes: type SemPols = [Int]
- NLP.GenI.Btypes: type Subst = Map String GeniVal
- NLP.GenI.Btypes: unify :: (Monad m) => [GeniVal] -> [GeniVal] -> m ([GeniVal], Subst)
- NLP.GenI.Btypes: unifyFeat :: (Monad m) => Flist -> Flist -> m (Flist, Subst)
- NLP.GenI.BtypesBinary: instance [overlap ok] (Binary a) => Binary (Ttree a)
- NLP.GenI.BtypesBinary: instance [overlap ok] Binary AvPair
- NLP.GenI.BtypesBinary: instance [overlap ok] Binary GNode
- NLP.GenI.BtypesBinary: instance [overlap ok] Binary GType
- NLP.GenI.BtypesBinary: instance [overlap ok] Binary GeniVal
- NLP.GenI.BtypesBinary: instance [overlap ok] Binary ILexEntry
- NLP.GenI.BtypesBinary: instance [overlap ok] Binary Ptype
- NLP.GenI.Builder: LemmaPlus :: String -> Flist -> LemmaPlus
- NLP.GenI.Builder: chart_size :: String
- NLP.GenI.Builder: class IafAble a
- NLP.GenI.Builder: data LemmaPlus
- NLP.GenI.Builder: dependentSem :: IafMap -> String -> Sem
- NLP.GenI.Builder: fromUniConst :: (Monad m) => GeniVal -> m String
- NLP.GenI.Builder: getIdx :: Flist -> [GeniVal]
- NLP.GenI.Builder: iafAcc :: (IafAble a) => a -> [String]
- NLP.GenI.Builder: iafBadSem :: (IafAble a) => IafMap -> SemBitMap -> BitVector -> (a -> BitVector) -> a -> BitVector
- NLP.GenI.Builder: iafInacc :: (IafAble a) => a -> [String]
- NLP.GenI.Builder: iafNewAcc :: (IafAble a) => a -> [String]
- NLP.GenI.Builder: iafSetAcc :: (IafAble a) => [String] -> a -> a
- NLP.GenI.Builder: iafSetInacc :: (IafAble a) => [String] -> a -> a
- NLP.GenI.Builder: initNullBuilder :: Input -> Params -> ((), Statistics)
- NLP.GenI.Builder: instance [overlap ok] Biplate UninflectedDisjunction GeniVal
- NLP.GenI.Builder: instance [overlap ok] Collectable UninflectedDisjunction
- NLP.GenI.Builder: instance [overlap ok] Data UninflectedDisjunction
- NLP.GenI.Builder: instance [overlap ok] DescendGeniVal UninflectedDisjunction
- NLP.GenI.Builder: instance [overlap ok] Eq LemmaPlus
- NLP.GenI.Builder: instance [overlap ok] JSON LemmaPlus
- NLP.GenI.Builder: instance [overlap ok] Ord LemmaPlus
- NLP.GenI.Builder: instance [overlap ok] Show LemmaPlus
- NLP.GenI.Builder: instance [overlap ok] Show UninflectedDisjunction
- NLP.GenI.Builder: instance [overlap ok] Typeable UninflectedDisjunction
- NLP.GenI.Builder: literalArgs :: Pred -> [GeniVal]
- NLP.GenI.Builder: lpFeats :: LemmaPlus -> Flist
- NLP.GenI.Builder: lpLemma :: LemmaPlus -> String
- NLP.GenI.Builder: modifyStats :: (Metric -> Metric) -> BuilderState st ()
- NLP.GenI.Builder: namedMetric :: String -> Metric
- NLP.GenI.Builder: nullBuilder :: Builder () (NullState ()) Params
- NLP.GenI.Builder: nullFilter :: (Monad s) => DispatchFilter s a
- NLP.GenI.Builder: num_comparisons :: String
- NLP.GenI.Builder: num_iterations :: String
- NLP.GenI.Builder: parsecToJSON :: (Monad m) => String -> CharParser () b -> String -> m b
- NLP.GenI.Builder: recalculateAccesibility :: (IafAble a) => a -> a
- NLP.GenI.Builder: semToIafMap :: Sem -> IafMap
- NLP.GenI.Builder: ts_iafFailure :: [String] -> [Pred] -> String
- NLP.GenI.Builder: type Derivation = TagDerivation
- NLP.GenI.Builder: type IafMap = Map String Sem
- NLP.GenI.Builder: type LemmaPlusSentence = [LemmaPlus]
- NLP.GenI.Builder: type NullState a = BuilderState () a
- NLP.GenI.Configuration: AdjOpts :: Optimisation
- NLP.GenI.Configuration: BatchDirFlg :: FilePath -> BatchDirFlg
- NLP.GenI.Configuration: DetectPolaritiesFlg :: (Set PolarityAttr) -> DetectPolaritiesFlg
- NLP.GenI.Configuration: DisableGuiFlg :: () -> DisableGuiFlg
- NLP.GenI.Configuration: DumpDerivationFlg :: () -> DumpDerivationFlg
- NLP.GenI.Configuration: EarlyDeathFlg :: () -> EarlyDeathFlg
- NLP.GenI.Configuration: EarlyNa :: Optimisation
- NLP.GenI.Configuration: ExtraPolaritiesFlg :: (Map PolarityKey Interval) -> ExtraPolaritiesFlg
- NLP.GenI.Configuration: FromStdinFlg :: () -> FromStdinFlg
- NLP.GenI.Configuration: GeniHand :: GrammarType
- NLP.GenI.Configuration: HelpFlg :: () -> HelpFlg
- NLP.GenI.Configuration: Iaf :: Optimisation
- NLP.GenI.Configuration: InstructionsFileFlg :: FilePath -> InstructionsFileFlg
- NLP.GenI.Configuration: LexiconFlg :: FilePath -> LexiconFlg
- NLP.GenI.Configuration: MacrosFlg :: FilePath -> MacrosFlg
- NLP.GenI.Configuration: MetricsFlg :: [String] -> MetricsFlg
- NLP.GenI.Configuration: MorphCmdFlg :: String -> MorphCmdFlg
- NLP.GenI.Configuration: MorphInfoFlg :: FilePath -> MorphInfoFlg
- NLP.GenI.Configuration: NoConstraints :: Optimisation
- NLP.GenI.Configuration: NoLoadTestSuiteFlg :: () -> NoLoadTestSuiteFlg
- NLP.GenI.Configuration: NullBuilder :: BuilderType
- NLP.GenI.Configuration: OptimisationsFlg :: [Optimisation] -> OptimisationsFlg
- NLP.GenI.Configuration: OutputFileFlg :: String -> OutputFileFlg
- NLP.GenI.Configuration: PartialFlg :: () -> PartialFlg
- NLP.GenI.Configuration: PolOpts :: Optimisation
- NLP.GenI.Configuration: Polarised :: Optimisation
- NLP.GenI.Configuration: PreAnchored :: GrammarType
- NLP.GenI.Configuration: PreCompiled :: GrammarType
- NLP.GenI.Configuration: Prms :: GrammarType -> BuilderType -> [Flag] -> Params
- NLP.GenI.Configuration: RankingConstraintsFlg :: FilePath -> RankingConstraintsFlg
- NLP.GenI.Configuration: RegressionTestModeFlg :: () -> RegressionTestModeFlg
- NLP.GenI.Configuration: RootFeatureFlg :: Flist -> RootFeatureFlg
- NLP.GenI.Configuration: RunUnitTestFlg :: () -> RunUnitTestFlg
- NLP.GenI.Configuration: SemFiltered :: Optimisation
- NLP.GenI.Configuration: SimpleBuilder :: BuilderType
- NLP.GenI.Configuration: SimpleOnePhaseBuilder :: BuilderType
- NLP.GenI.Configuration: StatsFileFlg :: FilePath -> StatsFileFlg
- NLP.GenI.Configuration: TestCaseFlg :: String -> TestCaseFlg
- NLP.GenI.Configuration: TestInstructionsFlg :: [Instruction] -> TestInstructionsFlg
- NLP.GenI.Configuration: TestSuiteFlg :: FilePath -> TestSuiteFlg
- NLP.GenI.Configuration: TimeoutFlg :: Integer -> TimeoutFlg
- NLP.GenI.Configuration: TracesFlg :: FilePath -> TracesFlg
- NLP.GenI.Configuration: VerboseModeFlg :: () -> VerboseModeFlg
- NLP.GenI.Configuration: VersionFlg :: () -> VersionFlg
- NLP.GenI.Configuration: ViewCmdFlg :: String -> ViewCmdFlg
- NLP.GenI.Configuration: data BatchDirFlg
- NLP.GenI.Configuration: data BuilderType
- NLP.GenI.Configuration: data DetectPolaritiesFlg
- NLP.GenI.Configuration: data DisableGuiFlg
- NLP.GenI.Configuration: data DumpDerivationFlg
- NLP.GenI.Configuration: data EarlyDeathFlg
- NLP.GenI.Configuration: data ExtraPolaritiesFlg
- NLP.GenI.Configuration: data Flag
- NLP.GenI.Configuration: data FromStdinFlg
- NLP.GenI.Configuration: data GrammarType
- NLP.GenI.Configuration: data HelpFlg
- NLP.GenI.Configuration: data InstructionsFileFlg
- NLP.GenI.Configuration: data LexiconFlg
- NLP.GenI.Configuration: data MacrosFlg
- NLP.GenI.Configuration: data MetricsFlg
- NLP.GenI.Configuration: data MorphCmdFlg
- NLP.GenI.Configuration: data MorphInfoFlg
- NLP.GenI.Configuration: data NoLoadTestSuiteFlg
- NLP.GenI.Configuration: data Optimisation
- NLP.GenI.Configuration: data OptimisationsFlg
- NLP.GenI.Configuration: data OutputFileFlg
- NLP.GenI.Configuration: data PartialFlg
- NLP.GenI.Configuration: data RankingConstraintsFlg
- NLP.GenI.Configuration: data RegressionTestModeFlg
- NLP.GenI.Configuration: data RootFeatureFlg
- NLP.GenI.Configuration: data RunUnitTestFlg
- NLP.GenI.Configuration: data StatsFileFlg
- NLP.GenI.Configuration: data TestCaseFlg
- NLP.GenI.Configuration: data TestInstructionsFlg
- NLP.GenI.Configuration: data TestSuiteFlg
- NLP.GenI.Configuration: data TimeoutFlg
- NLP.GenI.Configuration: data TracesFlg
- NLP.GenI.Configuration: data VerboseModeFlg
- NLP.GenI.Configuration: data VersionFlg
- NLP.GenI.Configuration: data ViewCmdFlg
- NLP.GenI.Configuration: getFlag :: (Show f, Show x, Typeable f, Typeable x) => (x -> f) -> [Flag] -> Maybe x
- NLP.GenI.Configuration: hasFlag :: (Typeable f, Typeable x) => (x -> f) -> [Flag] -> Bool
- NLP.GenI.Configuration: instance [overlap ok] Eq BatchDirFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq BuilderFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq BuilderType
- NLP.GenI.Configuration: instance [overlap ok] Eq DetectPolaritiesFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq DisableGuiFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq DumpDerivationFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq EarlyDeathFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq ExtraPolaritiesFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq Flag
- NLP.GenI.Configuration: instance [overlap ok] Eq FromStdinFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq GrammarType
- NLP.GenI.Configuration: instance [overlap ok] Eq GrammarTypeFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq HelpFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq InstructionsFileFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq LexiconFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq MacrosFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq MetricsFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq MorphCmdFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq MorphInfoFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq NoLoadTestSuiteFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq Optimisation
- NLP.GenI.Configuration: instance [overlap ok] Eq OptimisationsFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq OutputFileFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq PartialFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq RankingConstraintsFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq RegressionTestModeFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq RootFeatureFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq RunUnitTestFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq StatsFileFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq TestCaseFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq TestInstructionsFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq TestSuiteFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq TimeoutFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq TracesFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq VerboseModeFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq VersionFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq ViewCmdFlg
- NLP.GenI.Configuration: instance [overlap ok] Eq WeirdFlg
- NLP.GenI.Configuration: instance [overlap ok] Show BatchDirFlg
- NLP.GenI.Configuration: instance [overlap ok] Show BuilderFlg
- NLP.GenI.Configuration: instance [overlap ok] Show BuilderType
- NLP.GenI.Configuration: instance [overlap ok] Show DetectPolaritiesFlg
- NLP.GenI.Configuration: instance [overlap ok] Show DisableGuiFlg
- NLP.GenI.Configuration: instance [overlap ok] Show DumpDerivationFlg
- NLP.GenI.Configuration: instance [overlap ok] Show EarlyDeathFlg
- NLP.GenI.Configuration: instance [overlap ok] Show ExtraPolaritiesFlg
- NLP.GenI.Configuration: instance [overlap ok] Show Flag
- NLP.GenI.Configuration: instance [overlap ok] Show FromStdinFlg
- NLP.GenI.Configuration: instance [overlap ok] Show GrammarType
- NLP.GenI.Configuration: instance [overlap ok] Show GrammarTypeFlg
- NLP.GenI.Configuration: instance [overlap ok] Show HelpFlg
- NLP.GenI.Configuration: instance [overlap ok] Show InstructionsFileFlg
- NLP.GenI.Configuration: instance [overlap ok] Show LexiconFlg
- NLP.GenI.Configuration: instance [overlap ok] Show MacrosFlg
- NLP.GenI.Configuration: instance [overlap ok] Show MetricsFlg
- NLP.GenI.Configuration: instance [overlap ok] Show MorphCmdFlg
- NLP.GenI.Configuration: instance [overlap ok] Show MorphInfoFlg
- NLP.GenI.Configuration: instance [overlap ok] Show NoLoadTestSuiteFlg
- NLP.GenI.Configuration: instance [overlap ok] Show Optimisation
- NLP.GenI.Configuration: instance [overlap ok] Show OptimisationsFlg
- NLP.GenI.Configuration: instance [overlap ok] Show OutputFileFlg
- NLP.GenI.Configuration: instance [overlap ok] Show Params
- NLP.GenI.Configuration: instance [overlap ok] Show PartialFlg
- NLP.GenI.Configuration: instance [overlap ok] Show RankingConstraintsFlg
- NLP.GenI.Configuration: instance [overlap ok] Show RegressionTestModeFlg
- NLP.GenI.Configuration: instance [overlap ok] Show RootFeatureFlg
- NLP.GenI.Configuration: instance [overlap ok] Show RunUnitTestFlg
- NLP.GenI.Configuration: instance [overlap ok] Show StatsFileFlg
- NLP.GenI.Configuration: instance [overlap ok] Show TestCaseFlg
- NLP.GenI.Configuration: instance [overlap ok] Show TestInstructionsFlg
- NLP.GenI.Configuration: instance [overlap ok] Show TestSuiteFlg
- NLP.GenI.Configuration: instance [overlap ok] Show TimeoutFlg
- NLP.GenI.Configuration: instance [overlap ok] Show TracesFlg
- NLP.GenI.Configuration: instance [overlap ok] Show VerboseModeFlg
- NLP.GenI.Configuration: instance [overlap ok] Show VersionFlg
- NLP.GenI.Configuration: instance [overlap ok] Show ViewCmdFlg
- NLP.GenI.Configuration: instance [overlap ok] Show WeirdFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable BatchDirFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable BuilderFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable BuilderType
- NLP.GenI.Configuration: instance [overlap ok] Typeable DetectPolaritiesFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable DisableGuiFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable DumpDerivationFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable EarlyDeathFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable ExtraPolaritiesFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable Flag
- NLP.GenI.Configuration: instance [overlap ok] Typeable FromStdinFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable GrammarType
- NLP.GenI.Configuration: instance [overlap ok] Typeable GrammarTypeFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable HelpFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable InstructionsFileFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable LexiconFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable MacrosFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable MetricsFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable MorphCmdFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable MorphInfoFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable NoLoadTestSuiteFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable Optimisation
- NLP.GenI.Configuration: instance [overlap ok] Typeable OptimisationsFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable OutputFileFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable PartialFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable RankingConstraintsFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable RegressionTestModeFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable RootFeatureFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable RunUnitTestFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable StatsFileFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable TestCaseFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable TestInstructionsFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable TestSuiteFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable TimeoutFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable TracesFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable VerboseModeFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable VersionFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable ViewCmdFlg
- NLP.GenI.Configuration: instance [overlap ok] Typeable WeirdFlg
- NLP.GenI.Configuration: setFlag :: (Eq f, Show f, Show x, Typeable f, Typeable x) => (x -> f) -> x -> [Flag] -> [Flag]
- NLP.GenI.Configuration: type Instruction = (FilePath, Maybe [String])
- NLP.GenI.General: boundsCheck :: Int -> [a] -> Bool
- NLP.GenI.General: exitTimeout :: IO ()
- NLP.GenI.General: groupAndCount :: (Eq a, Ord a) => [a] -> [(a, Int)]
- NLP.GenI.General: instance [overlap ok] Eq AlphaNum
- NLP.GenI.General: instance [overlap ok] Ord AlphaNum
- NLP.GenI.General: instance [overlap ok] Typeable TimeOut
- NLP.GenI.General: lazySlurp :: ForeignPtr Word8 -> Int -> Int -> IO String
- NLP.GenI.General: multiGroupByFM :: (Ord b) => (a -> [b]) -> [a] -> (Map b [a])
- NLP.GenI.General: readFile' :: FilePath -> IO String
- NLP.GenI.General: withTimeout :: Integer -> IO a -> IO a -> IO a
- NLP.GenI.Geni: CompleteResult :: ResultType
- NLP.GenI.Geni: GeniResult :: LemmaPlusSentence -> [String] -> Derivation -> [GeniLexSel] -> Int -> [OtViolation] -> ResultType -> GeniResult
- NLP.GenI.Geni: PartialResult :: ResultType
- NLP.GenI.Geni: ST :: Params -> Macros -> Lexicon -> MorphFn -> SemInput -> String -> [TestCase] -> OtRanking -> [String] -> [String] -> ProgState
- NLP.GenI.Geni: chooseLexCand :: Lexicon -> Sem -> [ILexEntry]
- NLP.GenI.Geni: combine :: Macros -> Lexicon -> Tags
- NLP.GenI.Geni: data GeniResult
- NLP.GenI.Geni: data ProgState
- NLP.GenI.Geni: data ResultType
- NLP.GenI.Geni: emptyProgState :: Params -> ProgState
- NLP.GenI.Geni: getTraces :: ProgState -> String -> [String]
- NLP.GenI.Geni: gr :: ProgState -> Macros
- NLP.GenI.Geni: grDerivation :: GeniResult -> Derivation
- NLP.GenI.Geni: grLemmaSentence :: GeniResult -> LemmaPlusSentence
- NLP.GenI.Geni: grLexSelection :: GeniResult -> [GeniLexSel]
- NLP.GenI.Geni: grRanking :: GeniResult -> Int
- NLP.GenI.Geni: grRealisations :: GeniResult -> [String]
- NLP.GenI.Geni: grResultType :: GeniResult -> ResultType
- NLP.GenI.Geni: grViolations :: GeniResult -> [OtViolation]
- NLP.GenI.Geni: groupAndCount :: (Eq a, Ord a) => [a] -> [(a, Int)]
- NLP.GenI.Geni: initGeni :: ProgStateRef -> IO (Input)
- NLP.GenI.Geni: instance [overlap ok] Eq GeniLexSel
- NLP.GenI.Geni: instance [overlap ok] Eq GeniResult
- NLP.GenI.Geni: instance [overlap ok] Eq ResultType
- NLP.GenI.Geni: instance [overlap ok] Error LexCombineError
- NLP.GenI.Geni: instance [overlap ok] JSON GeniLexSel
- NLP.GenI.Geni: instance [overlap ok] JSON GeniResult
- NLP.GenI.Geni: instance [overlap ok] JSON ResultType
- NLP.GenI.Geni: instance [overlap ok] Ord GeniLexSel
- NLP.GenI.Geni: instance [overlap ok] Ord GeniResult
- NLP.GenI.Geni: instance [overlap ok] Ord ResultType
- NLP.GenI.Geni: instance [overlap ok] Show LexCombineError
- NLP.GenI.Geni: le :: ProgState -> Lexicon
- NLP.GenI.Geni: lemmaSentenceString :: GeniResult -> String
- NLP.GenI.Geni: loadEverything :: ProgStateRef -> IO ()
- NLP.GenI.Geni: loadGeniMacros :: ProgStateRef -> IO ()
- NLP.GenI.Geni: loadLexicon :: ProgStateRef -> IO ()
- NLP.GenI.Geni: loadRanking :: ProgStateRef -> IO ()
- NLP.GenI.Geni: loadTargetSemStr :: ProgStateRef -> String -> IO ()
- NLP.GenI.Geni: loadTestSuite :: ProgStateRef -> IO [TestCase]
- NLP.GenI.Geni: morphinf :: ProgState -> MorphFn
- NLP.GenI.Geni: pa :: ProgState -> Params
- NLP.GenI.Geni: prettyResult :: ProgState -> GeniResult -> String
- NLP.GenI.Geni: ranking :: ProgState -> OtRanking
- NLP.GenI.Geni: readRanking :: Bool -> FilePath -> IO OtRanking
- NLP.GenI.Geni: runGeni :: ProgStateRef -> Builder st it Params -> IO ([GeniResult], Statistics, st)
- NLP.GenI.Geni: runGeniWithSelector :: ProgStateRef -> Selector -> Builder st it Params -> IO ([GeniResult], Statistics, st)
- NLP.GenI.Geni: showRealisations :: [String] -> String
- NLP.GenI.Geni: tcase :: ProgState -> String
- NLP.GenI.Geni: traces :: ProgState -> [String]
- NLP.GenI.Geni: ts :: ProgState -> SemInput
- NLP.GenI.Geni: tsuite :: ProgState -> [TestCase]
- NLP.GenI.Geni: type ProgStateRef = IORef ProgState
- NLP.GenI.Geni: type Selector = ProgStateRef -> IO ([TagElem], [ILexEntry])
- NLP.GenI.Geni: warnings :: ProgState -> [String]
- NLP.GenI.GeniParsers: geniDerivations :: Parser [TestCaseOutput]
- NLP.GenI.GeniParsers: geniFeats :: Parser Flist
- NLP.GenI.GeniParsers: geniLanguageDef :: LanguageDef ()
- NLP.GenI.GeniParsers: geniLexicon :: Parser [ILexEntry]
- NLP.GenI.GeniParsers: geniMacros :: Parser [MTtree]
- NLP.GenI.GeniParsers: geniMorphInfo :: Parser [(String, Flist)]
- NLP.GenI.GeniParsers: geniPolarities :: Parser (Map PolarityKey Interval)
- NLP.GenI.GeniParsers: geniSemanticInput :: Parser (Sem, Flist, [LitConstr])
- NLP.GenI.GeniParsers: geniSemantics :: Parser Sem
- NLP.GenI.GeniParsers: geniTagElems :: Parser [TagElem]
- NLP.GenI.GeniParsers: geniTestSuite :: Parser [TestCase]
- NLP.GenI.GeniParsers: geniTestSuiteString :: Parser [String]
- NLP.GenI.GeniParsers: geniValue :: Parser GeniVal
- NLP.GenI.GeniParsers: geniWord :: Parser String
- NLP.GenI.GeniParsers: geniWords :: Parser String
- NLP.GenI.GeniParsers: instance [overlap ok] GeniShow SemInputString
- NLP.GenI.GeniParsers: parseFromFile :: Parser a -> SourceName -> IO (Either ParseError a)
- NLP.GenI.GeniParsers: tillEof :: Parser a -> Parser a
- NLP.GenI.GeniParsers: toSemInputString :: SemInput -> String -> SemInputString
- NLP.GenI.GeniShow: geniShowKeyword :: String -> ShowS
- NLP.GenI.GeniShow: geniShowSemInput :: SemInput -> ShowS
- NLP.GenI.GeniShow: instance [overlap ok] (GeniShow a) => GeniShow (Tree a)
- NLP.GenI.GeniShow: instance [overlap ok] (GeniShow a) => GeniShow (Ttree a)
- NLP.GenI.GeniShow: instance [overlap ok] (GeniShow a) => GeniShow [a]
- NLP.GenI.GeniShow: instance [overlap ok] GeniShow AvPair
- NLP.GenI.GeniShow: instance [overlap ok] GeniShow GNode
- NLP.GenI.GeniShow: instance [overlap ok] GeniShow GeniVal
- NLP.GenI.GeniShow: instance [overlap ok] GeniShow Pred
- NLP.GenI.GeniShow: instance [overlap ok] GeniShow Ptype
- NLP.GenI.GeniShow: instance [overlap ok] GeniShow TagElem
- NLP.GenI.GeniShow: instance [overlap ok] GeniShow TestCase
- NLP.GenI.GeniShow: parens :: String -> String
- NLP.GenI.GeniShow: squares :: String -> String
- NLP.GenI.GeniVal: GAnon :: GeniVal
- NLP.GenI.GeniVal: GConst :: [String] -> GeniVal
- NLP.GenI.GeniVal: GTestString :: String -> GTestString
- NLP.GenI.GeniVal: GTestString2 :: String -> GTestString2
- NLP.GenI.GeniVal: GVar :: String -> GeniVal
- NLP.GenI.GeniVal: fromGConst :: GeniVal -> [String]
- NLP.GenI.GeniVal: fromGTestString :: GTestString -> String
- NLP.GenI.GeniVal: fromGTestString2 :: GTestString2 -> String
- NLP.GenI.GeniVal: fromGVar :: GeniVal -> String
- NLP.GenI.GeniVal: instance [overlap ok] (Functor f, DescendGeniVal a) => DescendGeniVal (f a)
- NLP.GenI.GeniVal: instance [overlap ok] Arbitrary GTestString
- NLP.GenI.GeniVal: instance [overlap ok] Arbitrary GTestString2
- NLP.GenI.GeniVal: instance [overlap ok] Arbitrary GeniVal
- NLP.GenI.GeniVal: instance [overlap ok] Data GeniVal
- NLP.GenI.GeniVal: instance [overlap ok] DescendGeniVal GeniVal
- NLP.GenI.GeniVal: instance [overlap ok] Eq GeniVal
- NLP.GenI.GeniVal: instance [overlap ok] NFData GeniVal
- NLP.GenI.GeniVal: instance [overlap ok] Ord GeniVal
- NLP.GenI.GeniVal: instance [overlap ok] Show GeniVal
- NLP.GenI.GeniVal: instance [overlap ok] Typeable GeniVal
- NLP.GenI.GeniVal: instance [overlap ok] Uniplate GeniVal
- NLP.GenI.GeniVal: mergeSubst :: Subst -> Subst -> Subst
- NLP.GenI.GeniVal: newtype GTestString
- NLP.GenI.GeniVal: newtype GTestString2
- NLP.GenI.GeniVal: prependToSubst :: (String, GeniVal) -> Subst -> Subst
- NLP.GenI.GeniVal: prop_unify_anon :: [GeniVal] -> Bool
- NLP.GenI.GeniVal: prop_unify_self :: [GeniVal] -> Property
- NLP.GenI.GeniVal: prop_unify_sym :: [GeniVal] -> [GeniVal] -> Property
- NLP.GenI.GeniVal: qc_not_empty_GConst :: GeniVal -> Bool
- NLP.GenI.GeniVal: replaceMapG :: Subst -> GeniVal -> GeniVal
- NLP.GenI.GeniVal: replaceOne :: (DescendGeniVal a) => (String, GeniVal) -> a -> a
- NLP.GenI.GeniVal: replaceOneG :: (String, GeniVal) -> GeniVal -> GeniVal
- NLP.GenI.GeniVal: unifyOne :: GeniVal -> GeniVal -> UnificationResult
- NLP.GenI.Morphology: LemmaPlus :: String -> Flist -> LemmaPlus
- NLP.GenI.Morphology: data LemmaPlus
- NLP.GenI.Morphology: lpFeats :: LemmaPlus -> Flist
- NLP.GenI.Morphology: lpLemma :: LemmaPlus -> String
- NLP.GenI.Morphology: type LemmaPlusSentence = [LemmaPlus]
- NLP.GenI.Morphology: type MorphFn = Pred -> Maybe Flist
- NLP.GenI.OptimalityTheory: instance [overlap ok] Eq LexItem
- NLP.GenI.OptimalityTheory: instance [overlap ok] Eq OtConstraint
- NLP.GenI.OptimalityTheory: instance [overlap ok] Eq OtViolation
- NLP.GenI.OptimalityTheory: instance [overlap ok] Eq RankedOtConstraint
- NLP.GenI.OptimalityTheory: instance [overlap ok] Eq RankedOtConstraint2
- NLP.GenI.OptimalityTheory: instance [overlap ok] JSON OtConstraint
- NLP.GenI.OptimalityTheory: instance [overlap ok] JSON OtViolation
- NLP.GenI.OptimalityTheory: instance [overlap ok] JSON RankedOtConstraint
- NLP.GenI.OptimalityTheory: instance [overlap ok] Ord LexItem
- NLP.GenI.OptimalityTheory: instance [overlap ok] Ord OtViolation
- NLP.GenI.OptimalityTheory: instance [overlap ok] Ord RankedOtConstraint
- NLP.GenI.OptimalityTheory: instance [overlap ok] Ord RankedOtConstraint2
- NLP.GenI.OptimalityTheory: instance [overlap ok] Show LexItem
- NLP.GenI.OptimalityTheory: instance [overlap ok] Show OtConstraint
- NLP.GenI.OptimalityTheory: instance [overlap ok] Show OtViolation
- NLP.GenI.OptimalityTheory: instance [overlap ok] Show RankedOtConstraint
- NLP.GenI.Polarity: detectPolFeatures :: [TagElem] -> [String]
- NLP.GenI.Polarity: instance [overlap ok] (ShowLite a) => ShowLite [a]
- NLP.GenI.Polarity: instance [overlap ok] (ShowLite a, ShowLite b) => ShowLite (a, b)
- NLP.GenI.Polarity: instance [overlap ok] Eq PolState
- NLP.GenI.Polarity: instance [overlap ok] Ord PolState
- NLP.GenI.Polarity: instance [overlap ok] Show PolState
- NLP.GenI.Polarity: instance [overlap ok] ShowLite Char
- NLP.GenI.Polarity: instance [overlap ok] ShowLite Int
- NLP.GenI.Polarity: instance [overlap ok] ShowLite TagElem
- NLP.GenI.Polarity: showLite :: (ShowLite a) => a -> String
- NLP.GenI.Polarity: showLitePm :: PolMap -> String
- NLP.GenI.Polarity: showPolPaths :: BitVector -> String
- NLP.GenI.Polarity: showPolPaths' :: BitVector -> Int -> [Int]
- NLP.GenI.Polarity: type PolResult = ([AutDebug], PolAut, PolAut, Sem)
- NLP.GenI.PolarityTypes: PolarityKey :: String -> PolarityKey
- NLP.GenI.PolarityTypes: RestrictedPolarityAttr :: String -> String -> PolarityAttr
- NLP.GenI.PolarityTypes: SimplePolarityAttr :: String -> PolarityAttr
- NLP.GenI.PolarityTypes: _rpkCat :: PolarityAttr -> String
- NLP.GenI.PolarityTypes: data PolarityAttr
- NLP.GenI.PolarityTypes: fromPolarityKey :: PolarityKey -> String
- NLP.GenI.PolarityTypes: instance [overlap ok] Data PolarityKey
- NLP.GenI.PolarityTypes: instance [overlap ok] Eq PolarityAttr
- NLP.GenI.PolarityTypes: instance [overlap ok] Eq PolarityKey
- NLP.GenI.PolarityTypes: instance [overlap ok] Ord PolarityAttr
- NLP.GenI.PolarityTypes: instance [overlap ok] Ord PolarityKey
- NLP.GenI.PolarityTypes: instance [overlap ok] Show PolarityAttr
- NLP.GenI.PolarityTypes: instance [overlap ok] Show PolarityKey
- NLP.GenI.PolarityTypes: instance [overlap ok] Typeable PolarityAttr
- NLP.GenI.PolarityTypes: instance [overlap ok] Typeable PolarityKey
- NLP.GenI.PolarityTypes: newtype PolarityKey
- NLP.GenI.PolarityTypes: readPolarityAttrs :: String -> Set PolarityAttr
- NLP.GenI.PolarityTypes: rpkAtt :: PolarityAttr -> String
- NLP.GenI.PolarityTypes: spkAtt :: PolarityAttr -> String
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] Biplate (String, UninflectedDisjunction) GeniVal
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] Biplate SimpleGuiItem GeniVal
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] Biplate SimpleItem GeniVal
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] Data SimpleGuiItem
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] DescendGeniVal (String, UninflectedDisjunction)
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] DescendGeniVal SimpleGuiItem
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] DescendGeniVal SimpleItem
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] IafAble SimpleItem
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] Show GenerationPhase
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] Show SimpleGuiItem
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] Show SimpleItem
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] Show SimpleStatus
- NLP.GenI.Simple.SimpleBuilder: instance [overlap ok] Typeable SimpleGuiItem
- NLP.GenI.Simple.SimpleBuilder: siAccesible :: SimpleItem -> [String]
- NLP.GenI.Simple.SimpleBuilder: siFoot :: SimpleItem -> Maybe TagSite
- NLP.GenI.Simple.SimpleBuilder: siInaccessible :: SimpleItem -> [String]
- NLP.GenI.Simple.SimpleBuilder: siLeaves :: SimpleItem -> [(String, UninflectedDisjunction)]
- NLP.GenI.Simple.SimpleBuilder: siRoot :: SimpleItem -> TagSite
- NLP.GenI.Simple.SimpleBuilder: simpleBuilder_1p :: SimpleBuilder
- NLP.GenI.Simple.SimpleBuilder: simpleBuilder_2p :: SimpleBuilder
- NLP.GenI.Statistics: instance [overlap ok] JSON Statistics
- NLP.GenI.Statistics: instance [overlap ok] Show Metric
- NLP.GenI.Tags: DerivationStep :: Char -> String -> String -> String -> DerivationStep
- NLP.GenI.Tags: TE :: String -> String -> Integer -> Ptype -> Tree GNode -> Sem -> Map PolarityKey (Int, Int) -> Flist -> [String] -> [SemPols] -> TagElem
- NLP.GenI.Tags: TagSite :: String -> Flist -> Flist -> String -> TagSite
- NLP.GenI.Tags: addToTags :: Tags -> String -> TagElem -> Tags
- NLP.GenI.Tags: class TagItem t
- NLP.GenI.Tags: collect :: (Collectable a) => a -> Set String -> Set String
- NLP.GenI.Tags: data DerivationStep
- NLP.GenI.Tags: data TagElem
- NLP.GenI.Tags: data TagSite
- NLP.GenI.Tags: detectSites :: Tree GNode -> ([TagSite], [TagSite], [TagSite])
- NLP.GenI.Tags: dsChild :: DerivationStep -> String
- NLP.GenI.Tags: dsOp :: DerivationStep -> Char
- NLP.GenI.Tags: dsParent :: DerivationStep -> String
- NLP.GenI.Tags: dsParentSite :: DerivationStep -> String
- NLP.GenI.Tags: emptyTE :: TagElem
- NLP.GenI.Tags: idname :: TagElem -> String
- NLP.GenI.Tags: instance [overlap ok] Biplate (Maybe TagSite) GeniVal
- NLP.GenI.Tags: instance [overlap ok] Biplate TagElem GeniVal
- NLP.GenI.Tags: instance [overlap ok] Biplate TagSite GeniVal
- NLP.GenI.Tags: instance [overlap ok] Collectable TagElem
- NLP.GenI.Tags: instance [overlap ok] Data TagElem
- NLP.GenI.Tags: instance [overlap ok] Data TagSite
- NLP.GenI.Tags: instance [overlap ok] DescendGeniVal TagElem
- NLP.GenI.Tags: instance [overlap ok] DescendGeniVal TagSite
- NLP.GenI.Tags: instance [overlap ok] Eq DerivationStep
- NLP.GenI.Tags: instance [overlap ok] Eq TagElem
- NLP.GenI.Tags: instance [overlap ok] Eq TagSite
- NLP.GenI.Tags: instance [overlap ok] Idable TagElem
- NLP.GenI.Tags: instance [overlap ok] JSON DerivationStep
- NLP.GenI.Tags: instance [overlap ok] Ord DerivationStep
- NLP.GenI.Tags: instance [overlap ok] Ord TagElem
- NLP.GenI.Tags: instance [overlap ok] Ord TagSite
- NLP.GenI.Tags: instance [overlap ok] Show DerivationStep
- NLP.GenI.Tags: instance [overlap ok] Show TagElem
- NLP.GenI.Tags: instance [overlap ok] Show TagSite
- NLP.GenI.Tags: instance [overlap ok] TagItem TagElem
- NLP.GenI.Tags: instance [overlap ok] Typeable TagElem
- NLP.GenI.Tags: instance [overlap ok] Typeable TagSite
- NLP.GenI.Tags: mapBySem :: (TagItem t) => [t] -> Map Pred [t]
- NLP.GenI.Tags: setTidnums :: [TagElem] -> [TagElem]
- NLP.GenI.Tags: showTagSites :: [TagSite] -> String
- NLP.GenI.Tags: subsumedBy :: Sem -> Pred -> Bool
- NLP.GenI.Tags: tagLeaves :: TagElem -> [(String, UninflectedDisjunction)]
- NLP.GenI.Tags: tgIdName :: (TagItem t) => t -> String
- NLP.GenI.Tags: tgIdNum :: (TagItem t) => t -> Integer
- NLP.GenI.Tags: tgSemantics :: (TagItem t) => t -> Sem
- NLP.GenI.Tags: tidnum :: TagElem -> Integer
- NLP.GenI.Tags: tinterface :: TagElem -> Flist
- NLP.GenI.Tags: tpolarities :: TagElem -> Map PolarityKey (Int, Int)
- NLP.GenI.Tags: tsDown :: TagSite -> Flist
- NLP.GenI.Tags: tsName :: TagSite -> String
- NLP.GenI.Tags: tsOrigin :: TagSite -> String
- NLP.GenI.Tags: tsUp :: TagSite -> Flist
- NLP.GenI.Tags: ts_rootFeatureMismatch :: Flist -> String
- NLP.GenI.Tags: ts_semIncomplete :: [Pred] -> String
- NLP.GenI.Tags: ts_synIncomplete :: String
- NLP.GenI.Tags: ts_tbUnificationFailure :: String
- NLP.GenI.Tags: tsemantics :: TagElem -> Sem
- NLP.GenI.Tags: tsempols :: TagElem -> [SemPols]
- NLP.GenI.Tags: ttrace :: TagElem -> [String]
- NLP.GenI.Tags: ttree :: TagElem -> Tree GNode
- NLP.GenI.Tags: ttreename :: TagElem -> String
- NLP.GenI.Tags: ttype :: TagElem -> Ptype
- NLP.GenI.Tags: type TagDerivation = [DerivationStep]
- NLP.GenI.Tags: type Tags = Map String [TagElem]
+ BoolExp: And :: (BoolExp a) -> (BoolExp a) -> BoolExp a
+ BoolExp: Cond :: a -> BoolExp a
+ BoolExp: Not :: (BoolExp a) -> BoolExp a
+ BoolExp: Or :: (BoolExp a) -> (BoolExp a) -> BoolExp a
+ BoolExp: check :: (a -> Bool) -> BoolExp a -> Bool
+ BoolExp: data BoolExp a
+ Data.FullList: (!:) :: Listable l => a -> l a -> FullList a
+ Data.FullList: (++) :: FullList a -> FullList a -> FullList a
+ Data.FullList: class Listable l
+ Data.FullList: data FullList a
+ Data.FullList: fromFL :: FullList a -> [a]
+ Data.FullList: head :: FullList a -> a
+ Data.FullList: indeedFL :: [a] -> w -> (FullList a -> w) -> w
+ Data.FullList: sortNub :: (Eq a, Ord a) => FullList a -> FullList a
+ Data.FullList: tail :: FullList a -> [a]
+ Data.FullList.Internal: (!:) :: Listable l => a -> l a -> FullList a
+ Data.FullList.Internal: (++) :: FullList a -> FullList a -> FullList a
+ Data.FullList.Internal: FullList :: [a] -> FullList a
+ Data.FullList.Internal: class Listable l
+ Data.FullList.Internal: fromFL :: FullList a -> [a]
+ Data.FullList.Internal: head :: FullList a -> a
+ Data.FullList.Internal: indeedFL :: [a] -> w -> (FullList a -> w) -> w
+ Data.FullList.Internal: instance Binary a => Binary (FullList a)
+ Data.FullList.Internal: instance Data a => Data (FullList a)
+ Data.FullList.Internal: instance Eq a => Eq (FullList a)
+ Data.FullList.Internal: instance Functor FullList
+ Data.FullList.Internal: instance Listable FullList
+ Data.FullList.Internal: instance Listable []
+ Data.FullList.Internal: instance NFData a => NFData (FullList a)
+ Data.FullList.Internal: instance Ord a => Ord (FullList a)
+ Data.FullList.Internal: instance Show a => Show (FullList a)
+ Data.FullList.Internal: instance Typeable1 FullList
+ Data.FullList.Internal: newtype FullList a
+ Data.FullList.Internal: sortNub :: (Eq a, Ord a) => FullList a -> FullList a
+ Data.FullList.Internal: tail :: FullList a -> [a]
+ NLP.GenI: BadInputException :: String -> ParseError -> BadInputException
+ NLP.GenI: CompleteResult :: ResultType
+ NLP.GenI: GError :: GeniError -> GeniResult
+ NLP.GenI: GSuccess :: GeniSuccess -> GeniResult
+ NLP.GenI: GeniError :: [Text] -> GeniError
+ NLP.GenI: GeniLexSel :: Text -> [Text] -> GeniLexSel
+ NLP.GenI: GeniResults :: [GeniResult] -> [Text] -> Statistics -> GeniResults
+ NLP.GenI: GeniSuccess :: LemmaPlusSentence -> [Text] -> ResultType -> [Text] -> TagDerivation -> Integer -> [GeniLexSel] -> Int -> [OtViolation] -> GeniSuccess
+ NLP.GenI: PartialResult :: ResultType
+ NLP.GenI: ProgState :: Params -> Macros -> Lexicon -> MorphInputFn -> OtRanking -> [Text] -> ProgState
+ NLP.GenI: class Loadable x
+ NLP.GenI: data BadInputException
+ NLP.GenI: data GeniError
+ NLP.GenI: data GeniLexSel
+ NLP.GenI: data GeniResult
+ NLP.GenI: data GeniResults
+ NLP.GenI: data GeniSuccess
+ NLP.GenI: data ProgState
+ NLP.GenI: data ResultType
+ NLP.GenI: emptyProgState :: Params -> ProgState
+ NLP.GenI: extractResults :: ProgStateRef -> Builder st it Params -> st -> IO [GeniResult]
+ NLP.GenI: getTraces :: ProgState -> Text -> [Text]
+ NLP.GenI: gr :: ProgState -> Macros
+ NLP.GenI: grDerivation :: GeniSuccess -> TagDerivation
+ NLP.GenI: grGlobalWarnings :: GeniResults -> [Text]
+ NLP.GenI: grLemmaSentence :: GeniSuccess -> LemmaPlusSentence
+ NLP.GenI: grLexSelection :: GeniSuccess -> [GeniLexSel]
+ NLP.GenI: grOrigin :: GeniSuccess -> Integer
+ NLP.GenI: grRanking :: GeniSuccess -> Int
+ NLP.GenI: grRealisations :: GeniSuccess -> [Text]
+ NLP.GenI: grResultType :: GeniSuccess -> ResultType
+ NLP.GenI: grResults :: GeniResults -> [GeniResult]
+ NLP.GenI: grStatistics :: GeniResults -> Statistics
+ NLP.GenI: grViolations :: GeniSuccess -> [OtViolation]
+ NLP.GenI: grWarnings :: GeniSuccess -> [Text]
+ NLP.GenI: histogram :: Ord a => [a] -> Map a Int
+ NLP.GenI: initGeni :: ProgStateRef -> SemInput -> IO (Input, GeniWarnings)
+ NLP.GenI: instance Eq GeniError
+ NLP.GenI: instance Eq GeniLexSel
+ NLP.GenI: instance Eq GeniResult
+ NLP.GenI: instance Eq GeniSuccess
+ NLP.GenI: instance Eq ResultType
+ NLP.GenI: instance Exception BadInputException
+ NLP.GenI: instance JSON GeniError
+ NLP.GenI: instance JSON GeniLexSel
+ NLP.GenI: instance JSON GeniResult
+ NLP.GenI: instance JSON GeniSuccess
+ NLP.GenI: instance JSON ResultType
+ NLP.GenI: instance Loadable Lexicon
+ NLP.GenI: instance Loadable Macros
+ NLP.GenI: instance Loadable MorphFnL
+ NLP.GenI: instance Loadable OtRanking
+ NLP.GenI: instance Loadable PreAnchoredL
+ NLP.GenI: instance Loadable TestSuiteL
+ NLP.GenI: instance Loadable TracesL
+ NLP.GenI: instance NFData GeniError
+ NLP.GenI: instance NFData GeniLexSel
+ NLP.GenI: instance NFData GeniResult
+ NLP.GenI: instance NFData GeniSuccess
+ NLP.GenI: instance NFData ResultType
+ NLP.GenI: instance Ord GeniError
+ NLP.GenI: instance Ord GeniLexSel
+ NLP.GenI: instance Ord GeniResult
+ NLP.GenI: instance Ord GeniSuccess
+ NLP.GenI: instance Ord ResultType
+ NLP.GenI: instance Pretty GeniError
+ NLP.GenI: instance Show BadInputException
+ NLP.GenI: instance Typeable BadInputException
+ NLP.GenI: isSuccess :: GeniResult -> Bool
+ NLP.GenI: lParse :: Loadable x => FilePath -> String -> Either ParseError x
+ NLP.GenI: lSet :: Loadable x => x -> ProgState -> ProgState
+ NLP.GenI: lSummarise :: Loadable x => x -> String
+ NLP.GenI: le :: ProgState -> Lexicon
+ NLP.GenI: lemmaSentenceString :: GeniSuccess -> Text
+ NLP.GenI: loadEverything :: ProgStateRef -> IO ()
+ NLP.GenI: loadFromString :: Loadable a => ProgStateRef -> String -> String -> IO a
+ NLP.GenI: loadGeniMacros :: ProgStateRef -> IO Macros
+ NLP.GenI: loadLexicon :: ProgStateRef -> IO Lexicon
+ NLP.GenI: loadRanking :: ProgStateRef -> IO ()
+ NLP.GenI: loadTestSuite :: ProgStateRef -> IO [TestCase]
+ NLP.GenI: morphinf :: ProgState -> MorphInputFn
+ NLP.GenI: nlTrace :: GeniLexSel -> [Text]
+ NLP.GenI: nlTree :: GeniLexSel -> Text
+ NLP.GenI: pa :: ProgState -> Params
+ NLP.GenI: parseSemInput :: String -> Either ParseError SemInput
+ NLP.GenI: prettyResult :: ProgState -> GeniSuccess -> Text
+ NLP.GenI: ranking :: ProgState -> OtRanking
+ NLP.GenI: runGeni :: ProgStateRef -> SemInput -> Builder st it Params -> IO (GeniResults, st)
+ NLP.GenI: showRealisations :: [String] -> String
+ NLP.GenI: traces :: ProgState -> [Text]
+ NLP.GenI: type LexicalSelector = Macros -> Lexicon -> Sem -> IO LexicalSelection
+ NLP.GenI: type ProgStateRef = IORef ProgState
+ NLP.GenI.Builder: Active :: GenStatus
+ NLP.GenI.Builder: Error :: Text -> GenStatus
+ NLP.GenI.Builder: Filtered :: FilterStatus a
+ NLP.GenI.Builder: Finished :: GenStatus
+ NLP.GenI.Builder: NotFiltered :: a -> FilterStatus a
+ NLP.GenI.Builder: data FilterStatus a
+ NLP.GenI.Builder: data GenStatus
+ NLP.GenI.Builder: instance Collectable UninflectedDisjunction
+ NLP.GenI.Builder: instance Data UninflectedDisjunction
+ NLP.GenI.Builder: instance DescendGeniVal UninflectedDisjunction
+ NLP.GenI.Builder: instance NFData Input
+ NLP.GenI.Builder: instance Typeable UninflectedDisjunction
+ NLP.GenI.Builder: num_iterations, num_comparisons, chart_size :: String
+ NLP.GenI.Builder: type TagDerivation = [DerivationStep]
+ NLP.GenI.Configuration: Params :: GrammarType -> BuilderType -> Maybe MorphRealiser -> Maybe LexicalSelector -> [Flag] -> Params
+ NLP.GenI.Configuration: customMorph :: Params -> Maybe MorphRealiser
+ NLP.GenI.Configuration: customSelector :: Params -> Maybe LexicalSelector
+ NLP.GenI.Configuration: helpOption :: OptDescr Flag
+ NLP.GenI.Configuration: instance IsString YamlLight
+ NLP.GenI.Configuration: instance Read LogFmt
+ NLP.GenI.Configuration: instance Read LogTo
+ NLP.GenI.Configuration: instance Show LogFmt
+ NLP.GenI.Configuration: instance Show LogTo
+ NLP.GenI.Configuration: instance Show LoggerConfig
+ NLP.GenI.Configuration: lexiconOption, macrosOption :: OptDescr Flag
+ NLP.GenI.Configuration: modifyFlagP :: (Eq f, Typeable f, Typeable x) => (x -> f) -> (x -> x) -> Params -> Params
+ NLP.GenI.Configuration: readGlobalConfig :: IO (Maybe YamlLight)
+ NLP.GenI.Configuration: setLoggers :: YamlLight -> IO ()
+ NLP.GenI.Configuration: verboseOption :: OptDescr Flag
+ NLP.GenI.Console: consoleGeni :: ProgStateRef -> IO ()
+ NLP.GenI.Console: instance Typeable MNAME
+ NLP.GenI.Console: loadNextSuite :: ProgStateRef -> (FilePath, Maybe [Text]) -> IO [TestCase]
+ NLP.GenI.FeatureStructure: AvPair :: Text -> a -> AvPair a
+ NLP.GenI.FeatureStructure: alignFeat :: Flist GeniVal -> Flist GeniVal -> [(Text, GeniVal, GeniVal)]
+ NLP.GenI.FeatureStructure: alignFeatH :: Flist GeniVal -> Flist GeniVal -> [(Text, GeniVal, GeniVal)] -> [(Text, GeniVal, GeniVal)]
+ NLP.GenI.FeatureStructure: avAtt :: AvPair a -> Text
+ NLP.GenI.FeatureStructure: avVal :: AvPair a -> a
+ NLP.GenI.FeatureStructure: crushAvPair :: AvPair [GeniVal] -> Maybe (AvPair GeniVal)
+ NLP.GenI.FeatureStructure: crushFlist :: Flist [GeniVal] -> Maybe (Flist GeniVal)
+ NLP.GenI.FeatureStructure: data AvPair a
+ NLP.GenI.FeatureStructure: emptyFeatStruct :: FeatStruct a
+ NLP.GenI.FeatureStructure: fromFeatStruct :: FeatStruct a -> Flist a
+ NLP.GenI.FeatureStructure: instance Binary a => Binary (AvPair a)
+ NLP.GenI.FeatureStructure: instance Collectable a => Collectable (AvPair a)
+ NLP.GenI.FeatureStructure: instance Data a => Data (AvPair a)
+ NLP.GenI.FeatureStructure: instance DescendGeniVal a => DescendGeniVal (String, a)
+ NLP.GenI.FeatureStructure: instance DescendGeniVal v => DescendGeniVal (AvPair v)
+ NLP.GenI.FeatureStructure: instance DescendGeniVal v => DescendGeniVal ([String], Flist v)
+ NLP.GenI.FeatureStructure: instance Eq a => Eq (AvPair a)
+ NLP.GenI.FeatureStructure: instance GeniShow (AvPair GeniVal)
+ NLP.GenI.FeatureStructure: instance GeniShow (FeatStruct GeniVal)
+ NLP.GenI.FeatureStructure: instance GeniShow (Flist GeniVal)
+ NLP.GenI.FeatureStructure: instance NFData a => NFData (AvPair a)
+ NLP.GenI.FeatureStructure: instance Ord a => Ord (AvPair a)
+ NLP.GenI.FeatureStructure: instance Pretty (AvPair GeniVal)
+ NLP.GenI.FeatureStructure: instance Pretty (FeatStruct GeniVal)
+ NLP.GenI.FeatureStructure: instance Pretty (Flist GeniVal)
+ NLP.GenI.FeatureStructure: instance Typeable1 AvPair
+ NLP.GenI.FeatureStructure: mkFeatStruct :: Flist GeniVal -> FeatStruct GeniVal
+ NLP.GenI.FeatureStructure: sortFlist :: Flist a -> Flist a
+ NLP.GenI.FeatureStructure: type FeatStruct a = Map Text a
+ NLP.GenI.FeatureStructure: type Flist a = [AvPair a]
+ NLP.GenI.FeatureStructure: unifyFeat :: Monad m => Flist GeniVal -> Flist GeniVal -> m (Flist GeniVal, Subst)
+ NLP.GenI.Flag: AdjOpts :: Optimisation
+ NLP.GenI.Flag: BatchDirFlg :: FilePath -> BatchDirFlg
+ NLP.GenI.Flag: BuilderFlg :: BuilderType -> BuilderFlg
+ NLP.GenI.Flag: DetectPolaritiesFlg :: (Set PolarityAttr) -> DetectPolaritiesFlg
+ NLP.GenI.Flag: DisableGuiFlg :: () -> DisableGuiFlg
+ NLP.GenI.Flag: DumpDerivationFlg :: () -> DumpDerivationFlg
+ NLP.GenI.Flag: EarlyDeathFlg :: () -> EarlyDeathFlg
+ NLP.GenI.Flag: Flag :: (x -> f) -> x -> Flag
+ NLP.GenI.Flag: FromStdinFlg :: () -> FromStdinFlg
+ NLP.GenI.Flag: GeniHand :: GrammarType
+ NLP.GenI.Flag: GrammarTypeFlg :: GrammarType -> GrammarTypeFlg
+ NLP.GenI.Flag: HelpFlg :: () -> HelpFlg
+ NLP.GenI.Flag: InstructionsFileFlg :: FilePath -> InstructionsFileFlg
+ NLP.GenI.Flag: LexiconFlg :: FilePath -> LexiconFlg
+ NLP.GenI.Flag: MacrosFlg :: FilePath -> MacrosFlg
+ NLP.GenI.Flag: MaxResultsFlg :: Integer -> MaxResultsFlg
+ NLP.GenI.Flag: MaxStepsFlg :: Integer -> MaxStepsFlg
+ NLP.GenI.Flag: MetricsFlg :: [String] -> MetricsFlg
+ NLP.GenI.Flag: MorphCmdFlg :: String -> MorphCmdFlg
+ NLP.GenI.Flag: MorphInfoFlg :: FilePath -> MorphInfoFlg
+ NLP.GenI.Flag: NoConstraints :: Optimisation
+ NLP.GenI.Flag: NoLoadTestSuiteFlg :: () -> NoLoadTestSuiteFlg
+ NLP.GenI.Flag: OptimisationsFlg :: [Optimisation] -> OptimisationsFlg
+ NLP.GenI.Flag: OutputFileFlg :: String -> OutputFileFlg
+ NLP.GenI.Flag: PartialFlg :: () -> PartialFlg
+ NLP.GenI.Flag: PolOpts :: Optimisation
+ NLP.GenI.Flag: Polarised :: Optimisation
+ NLP.GenI.Flag: PreAnchored :: GrammarType
+ NLP.GenI.Flag: PreCompiled :: GrammarType
+ NLP.GenI.Flag: RankingConstraintsFlg :: FilePath -> RankingConstraintsFlg
+ NLP.GenI.Flag: RootFeatureFlg :: (Flist GeniVal) -> RootFeatureFlg
+ NLP.GenI.Flag: SimpleBuilder :: BuilderType
+ NLP.GenI.Flag: SimpleOnePhaseBuilder :: BuilderType
+ NLP.GenI.Flag: StatsFileFlg :: FilePath -> StatsFileFlg
+ NLP.GenI.Flag: TestCaseFlg :: Text -> TestCaseFlg
+ NLP.GenI.Flag: TestInstructionsFlg :: [Instruction] -> TestInstructionsFlg
+ NLP.GenI.Flag: TestSuiteFlg :: FilePath -> TestSuiteFlg
+ NLP.GenI.Flag: TimeoutFlg :: Int -> TimeoutFlg
+ NLP.GenI.Flag: TracesFlg :: FilePath -> TracesFlg
+ NLP.GenI.Flag: VerboseModeFlg :: () -> VerboseModeFlg
+ NLP.GenI.Flag: VersionFlg :: () -> VersionFlg
+ NLP.GenI.Flag: ViewCmdFlg :: String -> ViewCmdFlg
+ NLP.GenI.Flag: WeirdFlg :: String -> WeirdFlg
+ NLP.GenI.Flag: data BuilderType
+ NLP.GenI.Flag: data Flag
+ NLP.GenI.Flag: data GrammarType
+ NLP.GenI.Flag: data Optimisation
+ NLP.GenI.Flag: deleteFlag :: (Typeable f, Typeable x) => (x -> f) -> [Flag] -> [Flag]
+ NLP.GenI.Flag: getAllFlags :: (Typeable f, Typeable x) => (x -> f) -> [Flag] -> [x]
+ NLP.GenI.Flag: getFlag :: (Typeable f, Typeable x) => (x -> f) -> [Flag] -> Maybe x
+ NLP.GenI.Flag: hasFlag :: (Typeable f, Typeable x) => (x -> f) -> [Flag] -> Bool
+ NLP.GenI.Flag: instance Eq BatchDirFlg
+ NLP.GenI.Flag: instance Eq BuilderFlg
+ NLP.GenI.Flag: instance Eq BuilderType
+ NLP.GenI.Flag: instance Eq DetectPolaritiesFlg
+ NLP.GenI.Flag: instance Eq DisableGuiFlg
+ NLP.GenI.Flag: instance Eq DumpDerivationFlg
+ NLP.GenI.Flag: instance Eq EarlyDeathFlg
+ NLP.GenI.Flag: instance Eq Flag
+ NLP.GenI.Flag: instance Eq FromStdinFlg
+ NLP.GenI.Flag: instance Eq GrammarType
+ NLP.GenI.Flag: instance Eq GrammarTypeFlg
+ NLP.GenI.Flag: instance Eq HelpFlg
+ NLP.GenI.Flag: instance Eq InstructionsFileFlg
+ NLP.GenI.Flag: instance Eq LexiconFlg
+ NLP.GenI.Flag: instance Eq MacrosFlg
+ NLP.GenI.Flag: instance Eq MaxResultsFlg
+ NLP.GenI.Flag: instance Eq MaxStepsFlg
+ NLP.GenI.Flag: instance Eq MetricsFlg
+ NLP.GenI.Flag: instance Eq MorphCmdFlg
+ NLP.GenI.Flag: instance Eq MorphInfoFlg
+ NLP.GenI.Flag: instance Eq NoLoadTestSuiteFlg
+ NLP.GenI.Flag: instance Eq Optimisation
+ NLP.GenI.Flag: instance Eq OptimisationsFlg
+ NLP.GenI.Flag: instance Eq OutputFileFlg
+ NLP.GenI.Flag: instance Eq PartialFlg
+ NLP.GenI.Flag: instance Eq RankingConstraintsFlg
+ NLP.GenI.Flag: instance Eq RootFeatureFlg
+ NLP.GenI.Flag: instance Eq StatsFileFlg
+ NLP.GenI.Flag: instance Eq TestCaseFlg
+ NLP.GenI.Flag: instance Eq TestInstructionsFlg
+ NLP.GenI.Flag: instance Eq TestSuiteFlg
+ NLP.GenI.Flag: instance Eq TimeoutFlg
+ NLP.GenI.Flag: instance Eq TracesFlg
+ NLP.GenI.Flag: instance Eq VerboseModeFlg
+ NLP.GenI.Flag: instance Eq VersionFlg
+ NLP.GenI.Flag: instance Eq ViewCmdFlg
+ NLP.GenI.Flag: instance Eq WeirdFlg
+ NLP.GenI.Flag: instance Show BuilderType
+ NLP.GenI.Flag: instance Show GrammarType
+ NLP.GenI.Flag: instance Show Optimisation
+ NLP.GenI.Flag: instance Typeable BatchDirFlg
+ NLP.GenI.Flag: instance Typeable BuilderFlg
+ NLP.GenI.Flag: instance Typeable BuilderType
+ NLP.GenI.Flag: instance Typeable DetectPolaritiesFlg
+ NLP.GenI.Flag: instance Typeable DisableGuiFlg
+ NLP.GenI.Flag: instance Typeable DumpDerivationFlg
+ NLP.GenI.Flag: instance Typeable EarlyDeathFlg
+ NLP.GenI.Flag: instance Typeable Flag
+ NLP.GenI.Flag: instance Typeable FromStdinFlg
+ NLP.GenI.Flag: instance Typeable GrammarType
+ NLP.GenI.Flag: instance Typeable GrammarTypeFlg
+ NLP.GenI.Flag: instance Typeable HelpFlg
+ NLP.GenI.Flag: instance Typeable InstructionsFileFlg
+ NLP.GenI.Flag: instance Typeable LexiconFlg
+ NLP.GenI.Flag: instance Typeable MacrosFlg
+ NLP.GenI.Flag: instance Typeable MaxResultsFlg
+ NLP.GenI.Flag: instance Typeable MaxStepsFlg
+ NLP.GenI.Flag: instance Typeable MetricsFlg
+ NLP.GenI.Flag: instance Typeable MorphCmdFlg
+ NLP.GenI.Flag: instance Typeable MorphInfoFlg
+ NLP.GenI.Flag: instance Typeable NoLoadTestSuiteFlg
+ NLP.GenI.Flag: instance Typeable Optimisation
+ NLP.GenI.Flag: instance Typeable OptimisationsFlg
+ NLP.GenI.Flag: instance Typeable OutputFileFlg
+ NLP.GenI.Flag: instance Typeable PartialFlg
+ NLP.GenI.Flag: instance Typeable RankingConstraintsFlg
+ NLP.GenI.Flag: instance Typeable RootFeatureFlg
+ NLP.GenI.Flag: instance Typeable StatsFileFlg
+ NLP.GenI.Flag: instance Typeable TestCaseFlg
+ NLP.GenI.Flag: instance Typeable TestInstructionsFlg
+ NLP.GenI.Flag: instance Typeable TestSuiteFlg
+ NLP.GenI.Flag: instance Typeable TimeoutFlg
+ NLP.GenI.Flag: instance Typeable TracesFlg
+ NLP.GenI.Flag: instance Typeable VerboseModeFlg
+ NLP.GenI.Flag: instance Typeable VersionFlg
+ NLP.GenI.Flag: instance Typeable ViewCmdFlg
+ NLP.GenI.Flag: instance Typeable WeirdFlg
+ NLP.GenI.Flag: isFlag :: (Typeable f, Typeable x) => (x -> f) -> Flag -> Bool
+ NLP.GenI.Flag: modifyFlag :: (Eq f, Typeable f, Typeable x) => (x -> f) -> (x -> x) -> [Flag] -> [Flag]
+ NLP.GenI.Flag: newtype BatchDirFlg
+ NLP.GenI.Flag: newtype BuilderFlg
+ NLP.GenI.Flag: newtype DetectPolaritiesFlg
+ NLP.GenI.Flag: newtype DisableGuiFlg
+ NLP.GenI.Flag: newtype DumpDerivationFlg
+ NLP.GenI.Flag: newtype EarlyDeathFlg
+ NLP.GenI.Flag: newtype FromStdinFlg
+ NLP.GenI.Flag: newtype GrammarTypeFlg
+ NLP.GenI.Flag: newtype HelpFlg
+ NLP.GenI.Flag: newtype InstructionsFileFlg
+ NLP.GenI.Flag: newtype LexiconFlg
+ NLP.GenI.Flag: newtype MacrosFlg
+ NLP.GenI.Flag: newtype MaxResultsFlg
+ NLP.GenI.Flag: newtype MaxStepsFlg
+ NLP.GenI.Flag: newtype MetricsFlg
+ NLP.GenI.Flag: newtype MorphCmdFlg
+ NLP.GenI.Flag: newtype MorphInfoFlg
+ NLP.GenI.Flag: newtype NoLoadTestSuiteFlg
+ NLP.GenI.Flag: newtype OptimisationsFlg
+ NLP.GenI.Flag: newtype OutputFileFlg
+ NLP.GenI.Flag: newtype PartialFlg
+ NLP.GenI.Flag: newtype RankingConstraintsFlg
+ NLP.GenI.Flag: newtype RootFeatureFlg
+ NLP.GenI.Flag: newtype StatsFileFlg
+ NLP.GenI.Flag: newtype TestCaseFlg
+ NLP.GenI.Flag: newtype TestInstructionsFlg
+ NLP.GenI.Flag: newtype TestSuiteFlg
+ NLP.GenI.Flag: newtype TimeoutFlg
+ NLP.GenI.Flag: newtype TracesFlg
+ NLP.GenI.Flag: newtype VerboseModeFlg
+ NLP.GenI.Flag: newtype VersionFlg
+ NLP.GenI.Flag: newtype ViewCmdFlg
+ NLP.GenI.Flag: newtype WeirdFlg
+ NLP.GenI.Flag: setFlag :: (Eq f, Typeable f, Typeable x) => (x -> f) -> x -> [Flag] -> [Flag]
+ NLP.GenI.Flag: type Instruction = (FilePath, Maybe [Text])
+ NLP.GenI.General: buckets :: Ord b => (a -> b) -> [a] -> [(b, [a])]
+ NLP.GenI.General: clumpBy :: (a -> Int) -> Int -> [a] -> [[a]]
+ NLP.GenI.General: first3 :: (a -> a2) -> (a, b, c) -> (a2, b, c)
+ NLP.GenI.General: histogram :: Ord a => [a] -> Map a Int
+ NLP.GenI.General: instance Binary Text
+ NLP.GenI.General: instance Eq AlphaNum
+ NLP.GenI.General: instance JSON Text
+ NLP.GenI.General: instance Ord AlphaNum
+ NLP.GenI.General: isGeniIdentLetter :: Char -> Bool
+ NLP.GenI.General: mkLogname :: Typeable a => a -> String
+ NLP.GenI.General: prettyException :: IOException -> String
+ NLP.GenI.General: quoteString :: String -> String
+ NLP.GenI.General: quoteText :: Text -> Text
+ NLP.GenI.General: second3 :: (b -> b2) -> (a, b, c) -> (a, b2, c)
+ NLP.GenI.General: third3 :: (c -> c2) -> (a, b, c) -> (a, b, c2)
+ NLP.GenI.GeniShow: geniKeyword :: Text -> Text -> Text
+ NLP.GenI.GeniShow: geniShowText :: GeniShow a => a -> Text
+ NLP.GenI.GeniShow: geniShowTree :: GeniShow a => Int -> Tree a -> Text
+ NLP.GenI.GeniShow: instance GeniShow a => GeniShow (Tree a)
+ NLP.GenI.GeniVal: SuccessRep2 :: Text -> Text -> GeniVal -> UnificationResult
+ NLP.GenI.GeniVal: allSubsume :: Monad m => [GeniVal] -> [GeniVal] -> m ([GeniVal], Subst)
+ NLP.GenI.GeniVal: appendSubst :: Subst -> Subst -> Subst
+ NLP.GenI.GeniVal: class Collectable a
+ NLP.GenI.GeniVal: class Idable a
+ NLP.GenI.GeniVal: collect :: Collectable a => a -> Map CollectedVar Int -> Map CollectedVar Int
+ NLP.GenI.GeniVal: crushOne :: [GeniVal] -> Maybe GeniVal
+ NLP.GenI.GeniVal: finaliseVars :: (Collectable a, DescendGeniVal a) => Text -> a -> a
+ NLP.GenI.GeniVal: finaliseVarsById :: (Collectable a, DescendGeniVal a, Idable a) => a -> a
+ NLP.GenI.GeniVal: gConstraints :: GeniVal -> Maybe (FullList Text)
+ NLP.GenI.GeniVal: gLabel :: GeniVal -> Maybe Text
+ NLP.GenI.GeniVal: idOf :: Idable a => a -> Integer
+ NLP.GenI.GeniVal: mkGAnon :: GeniVal
+ NLP.GenI.GeniVal: mkGConst :: FullList Text -> GeniVal
+ NLP.GenI.GeniVal: mkGConstNone :: Text -> GeniVal
+ NLP.GenI.GeniVal: mkGVar :: Text -> Maybe (FullList Text) -> GeniVal
+ NLP.GenI.GeniVal: mkGVarNone :: Text -> GeniVal
+ NLP.GenI.GeniVal: singletonVal :: GeniVal -> Maybe Text
+ NLP.GenI.GeniVal: subsumeOne :: GeniVal -> GeniVal -> UnificationResult
+ NLP.GenI.GeniVal.Internal: Failure :: UnificationResult
+ NLP.GenI.GeniVal.Internal: GeniVal :: Maybe Text -> Maybe (FullList Text) -> GeniVal
+ NLP.GenI.GeniVal.Internal: SuccessRep :: Text -> GeniVal -> UnificationResult
+ NLP.GenI.GeniVal.Internal: SuccessRep2 :: Text -> Text -> GeniVal -> UnificationResult
+ NLP.GenI.GeniVal.Internal: SuccessSans :: GeniVal -> UnificationResult
+ NLP.GenI.GeniVal.Internal: allSubsume :: Monad m => [GeniVal] -> [GeniVal] -> m ([GeniVal], Subst)
+ NLP.GenI.GeniVal.Internal: anonymiseSingletons :: (Collectable a, DescendGeniVal a) => a -> a
+ NLP.GenI.GeniVal.Internal: appendSubst :: Subst -> Subst -> Subst
+ NLP.GenI.GeniVal.Internal: class Collectable a
+ NLP.GenI.GeniVal.Internal: class DescendGeniVal a
+ NLP.GenI.GeniVal.Internal: class Idable a
+ NLP.GenI.GeniVal.Internal: collect :: Collectable a => a -> Map CollectedVar Int -> Map CollectedVar Int
+ NLP.GenI.GeniVal.Internal: crushList :: [[GeniVal]] -> Maybe [GeniVal]
+ NLP.GenI.GeniVal.Internal: crushOne :: [GeniVal] -> Maybe GeniVal
+ NLP.GenI.GeniVal.Internal: data GeniVal
+ NLP.GenI.GeniVal.Internal: data UnificationResult
+ NLP.GenI.GeniVal.Internal: descendGeniVal :: DescendGeniVal a => (GeniVal -> GeniVal) -> a -> a
+ NLP.GenI.GeniVal.Internal: finaliseVars :: (Collectable a, DescendGeniVal a) => Text -> a -> a
+ NLP.GenI.GeniVal.Internal: finaliseVarsById :: (Collectable a, DescendGeniVal a, Idable a) => a -> a
+ NLP.GenI.GeniVal.Internal: gConstraints :: GeniVal -> Maybe (FullList Text)
+ NLP.GenI.GeniVal.Internal: gLabel :: GeniVal -> Maybe Text
+ NLP.GenI.GeniVal.Internal: idOf :: Idable a => a -> Integer
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] (Functor f, DescendGeniVal a) => DescendGeniVal (f a)
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] Binary GeniVal
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] Collectable GeniVal
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] Collectable a => Collectable (Maybe a)
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] Collectable a => Collectable [a]
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] Data GeniVal
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] DescendGeniVal GeniVal
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] Eq GeniVal
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] GeniShow GeniVal
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] NFData GeniVal
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] Ord GeniVal
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] Pretty GeniVal
+ NLP.GenI.GeniVal.Internal: instance [overlap ok] Typeable GeniVal
+ NLP.GenI.GeniVal.Internal: intersectConstraints :: Eq a => Maybe (FullList a) -> Maybe (FullList a) -> Maybe (Maybe (FullList a))
+ NLP.GenI.GeniVal.Internal: isAnon :: GeniVal -> Bool
+ NLP.GenI.GeniVal.Internal: isConst :: GeniVal -> Bool
+ NLP.GenI.GeniVal.Internal: isVar :: GeniVal -> Bool
+ NLP.GenI.GeniVal.Internal: mkGAnon :: GeniVal
+ NLP.GenI.GeniVal.Internal: mkGConst :: FullList Text -> GeniVal
+ NLP.GenI.GeniVal.Internal: mkGConstNone :: Text -> GeniVal
+ NLP.GenI.GeniVal.Internal: mkGVar :: Text -> Maybe (FullList Text) -> GeniVal
+ NLP.GenI.GeniVal.Internal: mkGVarNone :: Text -> GeniVal
+ NLP.GenI.GeniVal.Internal: prependToSubst :: (Text, GeniVal) -> Subst -> Subst
+ NLP.GenI.GeniVal.Internal: prettySubst :: Subst -> Text
+ NLP.GenI.GeniVal.Internal: replace :: DescendGeniVal a => Subst -> a -> a
+ NLP.GenI.GeniVal.Internal: replaceList :: DescendGeniVal a => [(Text, GeniVal)] -> a -> a
+ NLP.GenI.GeniVal.Internal: replaceMapG :: Subst -> GeniVal -> GeniVal
+ NLP.GenI.GeniVal.Internal: replaceOne :: DescendGeniVal a => (Text, GeniVal) -> a -> a
+ NLP.GenI.GeniVal.Internal: replaceOneG :: (Text, GeniVal) -> GeniVal -> GeniVal
+ NLP.GenI.GeniVal.Internal: singletonVal :: GeniVal -> Maybe Text
+ NLP.GenI.GeniVal.Internal: subsumeOne :: GeniVal -> GeniVal -> UnificationResult
+ NLP.GenI.GeniVal.Internal: type CollectedVar = (Text, Maybe (FullList Text))
+ NLP.GenI.GeniVal.Internal: type Subst = Map Text GeniVal
+ NLP.GenI.GeniVal.Internal: unify :: Monad m => [GeniVal] -> [GeniVal] -> m ([GeniVal], Subst)
+ NLP.GenI.GeniVal.Internal: unifyHelper :: Monad m => (GeniVal -> GeniVal -> UnificationResult) -> [GeniVal] -> [GeniVal] -> m ([GeniVal], Subst)
+ NLP.GenI.GeniVal.Internal: unifyOne :: GeniVal -> GeniVal -> UnificationResult
+ NLP.GenI.LexicalSelection: LexicalSelection :: [TagElem] -> [LexEntry] -> GeniWarnings -> LexicalSelection
+ NLP.GenI.LexicalSelection: _lemanchor :: Text
+ NLP.GenI.LexicalSelection: chooseCandI :: Sem -> [LexEntry] -> [LexEntry]
+ NLP.GenI.LexicalSelection: combineList :: Sem -> Macros -> LexEntry -> ([LexCombineError], [TagElem])
+ NLP.GenI.LexicalSelection: combineOne :: Sem -> LexEntry -> SchemaTree -> LexCombine [TagElem]
+ NLP.GenI.LexicalSelection: data LexicalSelection
+ NLP.GenI.LexicalSelection: defaultAnchoring :: Macros -> [LexEntry] -> Sem -> LexicalSelection
+ NLP.GenI.LexicalSelection: defaultLexicalChoice :: Lexicon -> Sem -> [LexEntry]
+ NLP.GenI.LexicalSelection: defaultLexicalSelection :: Macros -> Lexicon -> Sem -> LexicalSelection
+ NLP.GenI.LexicalSelection: defaultLexicalSelector :: Macros -> Lexicon -> Sem -> IO LexicalSelection
+ NLP.GenI.LexicalSelection: enrich :: LexEntry -> SchemaTree -> LexCombine SchemaTree
+ NLP.GenI.LexicalSelection: enrichBy :: SchemaTree -> PathEqPair -> LexCombine SchemaTree
+ NLP.GenI.LexicalSelection: enrichFeat :: AvPair GeniVal -> Flist [GeniVal] -> Maybe (Flist [GeniVal], Subst)
+ NLP.GenI.LexicalSelection: lexEquations :: LexEntry -> Writer [LexCombineError] ([AvPair GeniVal], [PathEqPair])
+ NLP.GenI.LexicalSelection: lexTell :: LexCombineError -> LexCombine ()
+ NLP.GenI.LexicalSelection: lsAnchored :: LexicalSelection -> [TagElem]
+ NLP.GenI.LexicalSelection: lsLexEntries :: LexicalSelection -> [LexEntry]
+ NLP.GenI.LexicalSelection: lsWarnings :: LexicalSelection -> GeniWarnings
+ NLP.GenI.LexicalSelection: matchNodeName :: NodePathEqLhs -> SchemaNode -> Bool
+ NLP.GenI.LexicalSelection: matchNodeNameHelper :: Text -> SchemaNode -> Bool
+ NLP.GenI.LexicalSelection: maybeEnrichBy :: SchemaTree -> PathEqPair -> Maybe (SchemaTree, Subst)
+ NLP.GenI.LexicalSelection: mergeSynonyms :: [LexEntry] -> [LexEntry]
+ NLP.GenI.LexicalSelection: missingCoanchors :: LexEntry -> SchemaTree -> [Text]
+ NLP.GenI.LexicalSelection: missingLexEntries :: [TagElem] -> [LexEntry] -> [LexEntry]
+ NLP.GenI.LexicalSelection: seekCoanchor :: NodePathEqLhs -> SchemaTree -> Maybe SchemaNode
+ NLP.GenI.LexicalSelection: setLemAnchors :: Tree (GNode GeniVal) -> Tree (GNode GeniVal)
+ NLP.GenI.LexicalSelection: setOrigin :: Text -> Tree (GNode v) -> Tree (GNode v)
+ NLP.GenI.LexicalSelection: type LexCombine a = MaybeT (Writer [LexCombineError]) a
+ NLP.GenI.LexicalSelection: type LexicalSelector = Macros -> Lexicon -> Sem -> IO LexicalSelection
+ NLP.GenI.LexicalSelection.Types: BoringError :: Text -> LexCombineError
+ NLP.GenI.LexicalSelection.Types: Bottom :: TopBottom
+ NLP.GenI.LexicalSelection.Types: EnrichError :: PathEqLhs -> LexCombineError2
+ NLP.GenI.LexicalSelection.Types: FamilyNotFoundError :: Text -> LexCombineError
+ NLP.GenI.LexicalSelection.Types: PeqFeat :: Text -> TopBottom -> Text -> NodePathEqLhs
+ NLP.GenI.LexicalSelection.Types: PeqInterface :: Text -> PathEqLhs
+ NLP.GenI.LexicalSelection.Types: PeqJust :: NodePathEqLhs -> PathEqLhs
+ NLP.GenI.LexicalSelection.Types: PeqLex :: Text -> NodePathEqLhs
+ NLP.GenI.LexicalSelection.Types: PeqUnknown :: Text -> PathEqLhs
+ NLP.GenI.LexicalSelection.Types: SchemaError :: [Text] -> LexCombineError2 -> LexCombineError
+ NLP.GenI.LexicalSelection.Types: StringError :: Text -> LexCombineError2
+ NLP.GenI.LexicalSelection.Types: Top :: TopBottom
+ NLP.GenI.LexicalSelection.Types: compressLexCombineErrors :: [LexCombineError] -> [LexCombineError]
+ NLP.GenI.LexicalSelection.Types: data LexCombineError
+ NLP.GenI.LexicalSelection.Types: data LexCombineError2
+ NLP.GenI.LexicalSelection.Types: data NodePathEqLhs
+ NLP.GenI.LexicalSelection.Types: data PathEqLhs
+ NLP.GenI.LexicalSelection.Types: data TopBottom
+ NLP.GenI.LexicalSelection.Types: instance Eq LexCombineError
+ NLP.GenI.LexicalSelection.Types: instance Eq LexCombineError2
+ NLP.GenI.LexicalSelection.Types: instance Eq NodePathEqLhs
+ NLP.GenI.LexicalSelection.Types: instance Eq PathEqLhs
+ NLP.GenI.LexicalSelection.Types: instance Eq TopBottom
+ NLP.GenI.LexicalSelection.Types: instance Ord LexCombineError2
+ NLP.GenI.LexicalSelection.Types: instance Ord NodePathEqLhs
+ NLP.GenI.LexicalSelection.Types: instance Ord PathEqLhs
+ NLP.GenI.LexicalSelection.Types: instance Ord TopBottom
+ NLP.GenI.LexicalSelection.Types: instance Poset LexCombineError
+ NLP.GenI.LexicalSelection.Types: instance Poset LexCombineError2
+ NLP.GenI.LexicalSelection.Types: instance Poset PathEqLhs
+ NLP.GenI.LexicalSelection.Types: instance Poset Text
+ NLP.GenI.LexicalSelection.Types: instance Pretty LexCombineError
+ NLP.GenI.LexicalSelection.Types: instance Pretty LexCombineError2
+ NLP.GenI.LexicalSelection.Types: parsePathEq :: Text -> Writer [LexCombineError] PathEqLhs
+ NLP.GenI.LexicalSelection.Types: showLexCombineError :: LexCombineError -> (Text, Text)
+ NLP.GenI.LexicalSelection.Types: showPathEqLhs :: PathEqLhs -> Text
+ NLP.GenI.LexicalSelection.Types: type PathEqPair = (NodePathEqLhs, GeniVal)
+ NLP.GenI.Lexicon: data LexEntry
+ NLP.GenI.Lexicon: fromLexLiteral :: Literal PolValue -> (Literal GeniVal, SemPols)
+ NLP.GenI.Lexicon: fromLexSem :: [Literal PolValue] -> (Sem, [SemPols])
+ NLP.GenI.Lexicon: iequations :: LexEntry -> Flist GeniVal
+ NLP.GenI.Lexicon: ifamname :: LexEntry -> Text
+ NLP.GenI.Lexicon: ifilters :: LexEntry -> Flist GeniVal
+ NLP.GenI.Lexicon: iinterface :: LexEntry -> Flist GeniVal
+ NLP.GenI.Lexicon: iparams :: LexEntry -> [GeniVal]
+ NLP.GenI.Lexicon: isemantics :: LexEntry -> Sem
+ NLP.GenI.Lexicon: isempols :: LexEntry -> [SemPols]
+ NLP.GenI.Lexicon: iword :: LexEntry -> FullList Text
+ NLP.GenI.Lexicon: mkFullLexEntry :: FullList Text -> Text -> [GeniVal] -> Flist GeniVal -> Flist GeniVal -> Flist GeniVal -> Sem -> [SemPols] -> LexEntry
+ NLP.GenI.Lexicon: mkLexEntry :: FullList Text -> Text -> [GeniVal] -> Flist GeniVal -> Flist GeniVal -> Flist GeniVal -> Sem -> LexEntry
+ NLP.GenI.Lexicon: type Lexicon = [LexEntry]
+ NLP.GenI.Lexicon: type PolValue = (GeniVal, Int)
+ NLP.GenI.Lexicon.Internal: LexEntry :: FullList Text -> Text -> [GeniVal] -> Flist GeniVal -> Flist GeniVal -> Flist GeniVal -> Sem -> [SemPols] -> LexEntry
+ NLP.GenI.Lexicon.Internal: data LexEntry
+ NLP.GenI.Lexicon.Internal: fromLexLiteral :: Literal PolValue -> (Literal GeniVal, SemPols)
+ NLP.GenI.Lexicon.Internal: fromLexSem :: [Literal PolValue] -> (Sem, [SemPols])
+ NLP.GenI.Lexicon.Internal: iequations :: LexEntry -> Flist GeniVal
+ NLP.GenI.Lexicon.Internal: ifamname :: LexEntry -> Text
+ NLP.GenI.Lexicon.Internal: ifilters :: LexEntry -> Flist GeniVal
+ NLP.GenI.Lexicon.Internal: iinterface :: LexEntry -> Flist GeniVal
+ NLP.GenI.Lexicon.Internal: instance Binary LexEntry
+ NLP.GenI.Lexicon.Internal: instance Collectable LexEntry
+ NLP.GenI.Lexicon.Internal: instance Data LexEntry
+ NLP.GenI.Lexicon.Internal: instance DescendGeniVal LexEntry
+ NLP.GenI.Lexicon.Internal: instance Eq LexEntry
+ NLP.GenI.Lexicon.Internal: instance GeniShow LexEntry
+ NLP.GenI.Lexicon.Internal: instance GeniShow [LexEntry]
+ NLP.GenI.Lexicon.Internal: instance NFData LexEntry
+ NLP.GenI.Lexicon.Internal: instance Pretty LexEntry
+ NLP.GenI.Lexicon.Internal: instance Typeable LexEntry
+ NLP.GenI.Lexicon.Internal: iparams :: LexEntry -> [GeniVal]
+ NLP.GenI.Lexicon.Internal: isemantics :: LexEntry -> Sem
+ NLP.GenI.Lexicon.Internal: isempols :: LexEntry -> [SemPols]
+ NLP.GenI.Lexicon.Internal: iword :: LexEntry -> FullList Text
+ NLP.GenI.Lexicon.Internal: mkFullLexEntry :: FullList Text -> Text -> [GeniVal] -> Flist GeniVal -> Flist GeniVal -> Flist GeniVal -> Sem -> [SemPols] -> LexEntry
+ NLP.GenI.Lexicon.Internal: mkLexEntry :: FullList Text -> Text -> [GeniVal] -> Flist GeniVal -> Flist GeniVal -> Flist GeniVal -> Sem -> LexEntry
+ NLP.GenI.Lexicon.Internal: type Lexicon = [LexEntry]
+ NLP.GenI.Lexicon.Internal: type PolValue = (GeniVal, Int)
+ NLP.GenI.Main: forceGuiFlag :: Params -> Params
+ NLP.GenI.Main: main :: IO ()
+ NLP.GenI.Main: mainWithState :: ProgState -> IO ()
+ NLP.GenI.Morphology: instance Typeable MNAME
+ NLP.GenI.Morphology.Types: LemmaPlus :: Text -> Flist GeniVal -> LemmaPlus
+ NLP.GenI.Morphology.Types: MorphOutput :: [Text] -> [Text] -> MorphOutput
+ NLP.GenI.Morphology.Types: data LemmaPlus
+ NLP.GenI.Morphology.Types: data MorphOutput
+ NLP.GenI.Morphology.Types: instance Eq LemmaPlus
+ NLP.GenI.Morphology.Types: instance Eq MorphOutput
+ NLP.GenI.Morphology.Types: instance JSON LemmaPlus
+ NLP.GenI.Morphology.Types: instance JSON MorphOutput
+ NLP.GenI.Morphology.Types: instance NFData LemmaPlus
+ NLP.GenI.Morphology.Types: instance NFData MorphOutput
+ NLP.GenI.Morphology.Types: instance Ord LemmaPlus
+ NLP.GenI.Morphology.Types: instance Ord MorphOutput
+ NLP.GenI.Morphology.Types: lpFeats :: LemmaPlus -> Flist GeniVal
+ NLP.GenI.Morphology.Types: lpLemma :: LemmaPlus -> Text
+ NLP.GenI.Morphology.Types: moRealisations :: MorphOutput -> [Text]
+ NLP.GenI.Morphology.Types: moWarnings :: MorphOutput -> [Text]
+ NLP.GenI.Morphology.Types: parsecToJSON :: Monad m => String -> Parser b -> String -> m b
+ NLP.GenI.Morphology.Types: type LemmaPlusSentence = [LemmaPlus]
+ NLP.GenI.Morphology.Types: type MorphInputFn = Literal GeniVal -> Maybe (Flist GeniVal)
+ NLP.GenI.Morphology.Types: type MorphRealiser = [LemmaPlusSentence] -> [MorphOutput]
+ NLP.GenI.OptimalityTheory: instance Eq LexItem
+ NLP.GenI.OptimalityTheory: instance Eq OtConstraint
+ NLP.GenI.OptimalityTheory: instance Eq OtViolation
+ NLP.GenI.OptimalityTheory: instance Eq RankedOtConstraint
+ NLP.GenI.OptimalityTheory: instance Eq RankedOtConstraint2
+ NLP.GenI.OptimalityTheory: instance JSON OtConstraint
+ NLP.GenI.OptimalityTheory: instance JSON OtViolation
+ NLP.GenI.OptimalityTheory: instance JSON RankedOtConstraint
+ NLP.GenI.OptimalityTheory: instance NFData OtConstraint
+ NLP.GenI.OptimalityTheory: instance NFData OtViolation
+ NLP.GenI.OptimalityTheory: instance NFData RankedOtConstraint
+ NLP.GenI.OptimalityTheory: instance Ord LexItem
+ NLP.GenI.OptimalityTheory: instance Ord OtViolation
+ NLP.GenI.OptimalityTheory: instance Ord RankedOtConstraint
+ NLP.GenI.OptimalityTheory: instance Ord RankedOtConstraint2
+ NLP.GenI.OptimalityTheory: instance Pretty OtConstraint
+ NLP.GenI.OptimalityTheory: instance Pretty RankedOtConstraint
+ NLP.GenI.OptimalityTheory: instance Show LexItem
+ NLP.GenI.OptimalityTheory: instance Show OtConstraint
+ NLP.GenI.OptimalityTheory: instance Show OtViolation
+ NLP.GenI.OptimalityTheory: instance Show RankedOtConstraint
+ NLP.GenI.Parser: geniDerivations :: Parser [TestCaseOutput]
+ NLP.GenI.Parser: geniFeats :: GeniValLike v => Parser (Flist v)
+ NLP.GenI.Parser: geniLanguageDef :: LanguageDef ()
+ NLP.GenI.Parser: geniLexicon :: Parser [LexEntry]
+ NLP.GenI.Parser: geniMacros :: Parser [SchemaTree]
+ NLP.GenI.Parser: geniMorphInfo :: Parser [(Text, Flist GeniVal)]
+ NLP.GenI.Parser: geniSemanticInput :: Parser (Sem, Flist GeniVal, [LitConstr])
+ NLP.GenI.Parser: geniSemantics :: Parser Sem
+ NLP.GenI.Parser: geniTagElems :: Parser [TagElem]
+ NLP.GenI.Parser: geniTestSuite :: Parser [TestCase]
+ NLP.GenI.Parser: geniTestSuiteString :: Parser [Text]
+ NLP.GenI.Parser: geniValue :: Parser GeniVal
+ NLP.GenI.Parser: geniWord :: Parser Text
+ NLP.GenI.Parser: geniWords :: Parser Text
+ NLP.GenI.Parser: instance Eq Annotation
+ NLP.GenI.Parser: instance GeniShow SemInputString
+ NLP.GenI.Parser: instance GeniValLike GeniVal
+ NLP.GenI.Parser: instance GeniValLike [GeniVal]
+ NLP.GenI.Parser: parseFromFile :: Parser a -> SourceName -> IO (Either ParseError a)
+ NLP.GenI.Parser: tillEof :: Parser a -> Parser a
+ NLP.GenI.Parser: toSemInputString :: SemInput -> Text -> SemInputString
+ NLP.GenI.Polarity: PolResult :: [AutDebug] -> PolAut -> PolAut -> Sem -> PolResult
+ NLP.GenI.Polarity: data PolResult
+ NLP.GenI.Polarity: instance Eq PolState
+ NLP.GenI.Polarity: instance Ord PolState
+ NLP.GenI.Polarity: instance Show PolState
+ NLP.GenI.Polarity: prFinal :: PolResult -> PolAut
+ NLP.GenI.Polarity: prInitial :: PolResult -> PolAut
+ NLP.GenI.Polarity: prIntermediate :: PolResult -> [AutDebug]
+ NLP.GenI.Polarity: prSem :: PolResult -> Sem
+ NLP.GenI.Polarity: prettyPolPaths :: BitVector -> Text
+ NLP.GenI.Polarity: prettyPolPaths' :: BitVector -> Int -> [Int]
+ NLP.GenI.Polarity: suggestPolFeatures :: [TagElem] -> [Text]
+ NLP.GenI.Polarity.Internal: PD_Just :: [(PolarityKey, Interval)] -> PolarityDetectionResult
+ NLP.GenI.Polarity.Internal: PD_Nothing :: PolarityDetectionResult
+ NLP.GenI.Polarity.Internal: PD_Unconstrained :: (Text, Interval) -> PolarityDetectionResult
+ NLP.GenI.Polarity.Internal: PD_UserError :: String -> PolarityDetectionResult
+ NLP.GenI.Polarity.Internal: __cat__, __idx__ :: Text
+ NLP.GenI.Polarity.Internal: addPols :: [(PolarityKey, Interval)] -> PolMap -> PolMap
+ NLP.GenI.Polarity.Internal: convertUnconstrainedPolarities :: [PolarityKey] -> PolMap -> PolMap
+ NLP.GenI.Polarity.Internal: data PolarityDetectionResult
+ NLP.GenI.Polarity.Internal: detectPolarity :: Int -> PolarityAttr -> FeatStruct GeniVal -> FeatStruct GeniVal -> PolarityDetectionResult
+ NLP.GenI.Polarity.Internal: detectPolsH :: Set PolarityAttr -> TagElem -> [(PolarityKey, Interval)]
+ NLP.GenI.Polarity.Internal: detectRootCompensation :: Set PolarityAttr -> FeatStruct GeniVal -> PolMap
+ NLP.GenI.Polarity.Internal: nubAut :: (Ord ab, Ord st) => NFA st ab -> NFA st ab
+ NLP.GenI.Polarity.Internal: pdResults :: [PolarityDetectionResult] -> [(PolarityKey, Interval)]
+ NLP.GenI.Polarity.Internal: pdToList :: (String -> String) -> PolarityDetectionResult -> [(PolarityKey, Interval)]
+ NLP.GenI.Polarity.Internal: polarityKeys :: [TagElem] -> PolMap -> [PolarityKey]
+ NLP.GenI.Polarity.Internal: substNodes :: TagElem -> [GNode GeniVal]
+ NLP.GenI.Polarity.Internal: substTops :: TagElem -> [Flist GeniVal]
+ NLP.GenI.Polarity.Internal: toZero :: Int -> Interval
+ NLP.GenI.Polarity.Internal: type PolMap = Map PolarityKey Interval
+ NLP.GenI.Polarity.Internal: type SemMap = Map (Literal GeniVal) [TagElem]
+ NLP.GenI.Polarity.Types: PolarityKeyAv :: Text -> Text -> PolarityKey
+ NLP.GenI.Polarity.Types: PolarityKeyStr :: Text -> PolarityKey
+ NLP.GenI.Polarity.Types: PolarityKeyVar :: Text -> PolarityKey
+ NLP.GenI.Polarity.Types: RestrictedPolarityAttr :: Text -> Text -> PolarityAttr
+ NLP.GenI.Polarity.Types: SimplePolarityAttr :: Text -> PolarityAttr
+ NLP.GenI.Polarity.Types: _rpkCat :: PolarityAttr -> Text
+ NLP.GenI.Polarity.Types: data PolarityAttr
+ NLP.GenI.Polarity.Types: data PolarityKey
+ NLP.GenI.Polarity.Types: instance Data PolarityKey
+ NLP.GenI.Polarity.Types: instance Eq PolarityAttr
+ NLP.GenI.Polarity.Types: instance Eq PolarityKey
+ NLP.GenI.Polarity.Types: instance NFData PolarityAttr
+ NLP.GenI.Polarity.Types: instance NFData PolarityKey
+ NLP.GenI.Polarity.Types: instance Ord PolarityAttr
+ NLP.GenI.Polarity.Types: instance Ord PolarityKey
+ NLP.GenI.Polarity.Types: instance Pretty PolarityKey
+ NLP.GenI.Polarity.Types: instance Show PolarityAttr
+ NLP.GenI.Polarity.Types: instance Typeable PolarityAttr
+ NLP.GenI.Polarity.Types: instance Typeable PolarityKey
+ NLP.GenI.Polarity.Types: readPolarityAttrs :: String -> Set PolarityAttr
+ NLP.GenI.Polarity.Types: rpkAtt :: PolarityAttr -> Text
+ NLP.GenI.Polarity.Types: showPolarityAttrs :: Set PolarityAttr -> String
+ NLP.GenI.Polarity.Types: spkAtt :: PolarityAttr -> Text
+ NLP.GenI.Polarity.Types: type SemPols = [Int]
+ NLP.GenI.Pretty: (<+>) :: Text -> Text -> Text
+ NLP.GenI.Pretty: (<>) :: Text -> Text -> Text
+ NLP.GenI.Pretty: above :: Text -> Text -> Text
+ NLP.GenI.Pretty: between :: Text -> Text -> Text -> Text
+ NLP.GenI.Pretty: class Pretty a where pretty = pack . prettyStr prettyStr = unpack . pretty
+ NLP.GenI.Pretty: instance Pretty Int
+ NLP.GenI.Pretty: instance Pretty Integer
+ NLP.GenI.Pretty: instance Pretty String
+ NLP.GenI.Pretty: parens :: Text -> Text
+ NLP.GenI.Pretty: pretty :: Pretty a => a -> Text
+ NLP.GenI.Pretty: prettyCount :: (a -> Text) -> Text -> (a, Int) -> Text
+ NLP.GenI.Pretty: prettyStr :: Pretty a => a -> String
+ NLP.GenI.Pretty: squares :: Text -> Text
+ NLP.GenI.Semantics: Literal :: gv -> gv -> [gv] -> Literal gv
+ NLP.GenI.Semantics: boringLiteral :: Literal GeniVal -> Maybe Text
+ NLP.GenI.Semantics: class HasConstants a
+ NLP.GenI.Semantics: compareOnLiteral :: Ord a => Literal a -> Literal a -> Ordering
+ NLP.GenI.Semantics: constants :: HasConstants a => a -> Int
+ NLP.GenI.Semantics: data Literal gv
+ NLP.GenI.Semantics: emptyLiteral :: Literal GeniVal
+ NLP.GenI.Semantics: instance Binary g => Binary (Literal g)
+ NLP.GenI.Semantics: instance Collectable a => Collectable (Literal a)
+ NLP.GenI.Semantics: instance Data gv => Data (Literal gv)
+ NLP.GenI.Semantics: instance DescendGeniVal a => DescendGeniVal (Literal a)
+ NLP.GenI.Semantics: instance Eq gv => Eq (Literal gv)
+ NLP.GenI.Semantics: instance GeniShow (Literal GeniVal)
+ NLP.GenI.Semantics: instance GeniShow Sem
+ NLP.GenI.Semantics: instance GeniShow SemInput
+ NLP.GenI.Semantics: instance HasConstants (Literal GeniVal)
+ NLP.GenI.Semantics: instance HasConstants GeniVal
+ NLP.GenI.Semantics: instance HasConstants a => HasConstants [a]
+ NLP.GenI.Semantics: instance NFData g => NFData (Literal g)
+ NLP.GenI.Semantics: instance Ord gv => Ord (Literal gv)
+ NLP.GenI.Semantics: instance Pretty (Literal GeniVal)
+ NLP.GenI.Semantics: instance Pretty Sem
+ NLP.GenI.Semantics: instance Pretty SemInput
+ NLP.GenI.Semantics: instance Typeable1 Literal
+ NLP.GenI.Semantics: isInternalHandle :: Text -> Bool
+ NLP.GenI.Semantics: lArgs :: Literal gv -> [gv]
+ NLP.GenI.Semantics: lHandle :: Literal gv -> gv
+ NLP.GenI.Semantics: lPredicate :: Literal gv -> gv
+ NLP.GenI.Semantics: literalCount :: [Literal GeniVal] -> Map Text Int
+ NLP.GenI.Semantics: removeConstraints :: SemInput -> SemInput
+ NLP.GenI.Semantics: sortByAmbiguity :: Sem -> Sem
+ NLP.GenI.Semantics: sortSem :: Ord a => [Literal a] -> [Literal a]
+ NLP.GenI.Semantics: subsumeLiteral :: Literal GeniVal -> Literal GeniVal -> Maybe (Literal GeniVal, Subst)
+ NLP.GenI.Semantics: subsumeSem :: Sem -> Sem -> [(Sem, Subst)]
+ NLP.GenI.Semantics: subsumeSemH :: Sem -> Sem -> [(Sem, Subst)]
+ NLP.GenI.Semantics: type LitConstr = (Literal GeniVal, [Text])
+ NLP.GenI.Semantics: type Sem = [Literal GeniVal]
+ NLP.GenI.Semantics: type SemInput = (Sem, Flist GeniVal, [LitConstr])
+ NLP.GenI.Semantics: unifyLiteral :: Literal GeniVal -> Literal GeniVal -> Maybe (Literal GeniVal, Subst)
+ NLP.GenI.Semantics: unifySem :: Sem -> Sem -> [(Sem, Subst)]
+ NLP.GenI.Semantics: unifySemH :: Sem -> Sem -> [(Sem, Subst)]
+ NLP.GenI.Simple.SimpleBuilder: instance Data SimpleGuiItem
+ NLP.GenI.Simple.SimpleBuilder: instance DescendGeniVal (Text, UninflectedDisjunction)
+ NLP.GenI.Simple.SimpleBuilder: instance DescendGeniVal SimpleItem
+ NLP.GenI.Simple.SimpleBuilder: instance Show GenerationPhase
+ NLP.GenI.Simple.SimpleBuilder: instance Typeable SimpleGuiItem
+ NLP.GenI.Simple.SimpleBuilder: siFoot_ :: SimpleItem -> Maybe NodeName
+ NLP.GenI.Simple.SimpleBuilder: siRoot_ :: SimpleItem -> NodeName
+ NLP.GenI.Simple.SimpleBuilder: simpleBuilder_2p, simpleBuilder_1p :: SimpleBuilder
+ NLP.GenI.Simple.SimpleBuilder: testCanAdjoin :: SimpleItem -> TagSite -> Maybe (TagSite, TagSite, Subst)
+ NLP.GenI.Simple.SimpleBuilder: testEmptySimpleGuiItem :: SimpleGuiItem
+ NLP.GenI.Simple.SimpleBuilder: testIapplyAdjNode :: Bool -> SimpleItem -> SimpleItem -> Maybe SimpleItem
+ NLP.GenI.Statistics: instance JSON Statistics
+ NLP.GenI.Statistics: instance NFData Metric
+ NLP.GenI.Statistics: instance NFData Statistics
+ NLP.GenI.Statistics: instance Show Metric
+ NLP.GenI.Tag: AdjunctionStep :: Text -> Text -> Text -> DerivationStep
+ NLP.GenI.Tag: InitStep :: Text -> DerivationStep
+ NLP.GenI.Tag: SubstitutionStep :: Text -> Text -> Text -> DerivationStep
+ NLP.GenI.Tag: TE :: Text -> Text -> Integer -> Ptype -> Tree (GNode GeniVal) -> Sem -> Map PolarityKey (Int, Int) -> Flist GeniVal -> [Text] -> [SemPols] -> TagElem
+ NLP.GenI.Tag: TagSite :: Text -> Flist GeniVal -> Flist GeniVal -> Text -> TagSite
+ NLP.GenI.Tag: addToTags :: Tags -> String -> TagElem -> Tags
+ NLP.GenI.Tag: class TagItem t
+ NLP.GenI.Tag: collect :: Collectable a => a -> Map CollectedVar Int -> Map CollectedVar Int
+ NLP.GenI.Tag: data DerivationStep
+ NLP.GenI.Tag: data TagElem
+ NLP.GenI.Tag: data TagSite
+ NLP.GenI.Tag: detectSites :: Tree (GNode GeniVal) -> ([NodeName], [NodeName], [NodeName])
+ NLP.GenI.Tag: dsChild :: DerivationStep -> Text
+ NLP.GenI.Tag: dsParent :: DerivationStep -> Maybe Text
+ NLP.GenI.Tag: dsParentSite :: DerivationStep -> Maybe Text
+ NLP.GenI.Tag: getLexeme :: GNode GeniVal -> [Text]
+ NLP.GenI.Tag: idname :: TagElem -> Text
+ NLP.GenI.Tag: instance Collectable TagElem
+ NLP.GenI.Tag: instance Data TagElem
+ NLP.GenI.Tag: instance Data TagSite
+ NLP.GenI.Tag: instance DescendGeniVal TagElem
+ NLP.GenI.Tag: instance DescendGeniVal TagSite
+ NLP.GenI.Tag: instance Eq DerivationStep
+ NLP.GenI.Tag: instance Eq TagElem
+ NLP.GenI.Tag: instance Eq TagSite
+ NLP.GenI.Tag: instance GeniShow TagElem
+ NLP.GenI.Tag: instance GeniShow [TagElem]
+ NLP.GenI.Tag: instance Idable TagElem
+ NLP.GenI.Tag: instance JSON DerivationStep
+ NLP.GenI.Tag: instance NFData DerivationStep
+ NLP.GenI.Tag: instance NFData TagElem
+ NLP.GenI.Tag: instance Ord DerivationStep
+ NLP.GenI.Tag: instance Ord TagElem
+ NLP.GenI.Tag: instance Ord TagSite
+ NLP.GenI.Tag: instance Pretty [TagSite]
+ NLP.GenI.Tag: instance Show DerivationStep
+ NLP.GenI.Tag: instance TagItem TagElem
+ NLP.GenI.Tag: instance Typeable TagElem
+ NLP.GenI.Tag: instance Typeable TagSite
+ NLP.GenI.Tag: mapBySem :: TagItem t => [t] -> Map (Literal GeniVal) [t]
+ NLP.GenI.Tag: plugTree :: Tree NodeName -> NodeName -> Tree NodeName -> Tree NodeName
+ NLP.GenI.Tag: setTidnums :: [TagElem] -> [TagElem]
+ NLP.GenI.Tag: spliceTree :: NodeName -> Tree NodeName -> NodeName -> Tree NodeName -> Tree NodeName
+ NLP.GenI.Tag: tagLeaves :: TagElem -> [(NodeName, UninflectedDisjunction)]
+ NLP.GenI.Tag: tgIdName :: TagItem t => t -> Text
+ NLP.GenI.Tag: tgIdNum :: TagItem t => t -> Integer
+ NLP.GenI.Tag: tgSemantics :: TagItem t => t -> Sem
+ NLP.GenI.Tag: tgTree :: TagItem t => t -> Tree (GNode GeniVal)
+ NLP.GenI.Tag: tidnum :: TagElem -> Integer
+ NLP.GenI.Tag: tinterface :: TagElem -> Flist GeniVal
+ NLP.GenI.Tag: toTagSite :: GNode GeniVal -> TagSite
+ NLP.GenI.Tag: tpolarities :: TagElem -> Map PolarityKey (Int, Int)
+ NLP.GenI.Tag: tsDown :: TagSite -> Flist GeniVal
+ NLP.GenI.Tag: tsName :: TagSite -> Text
+ NLP.GenI.Tag: tsOrigin :: TagSite -> Text
+ NLP.GenI.Tag: tsUp :: TagSite -> Flist GeniVal
+ NLP.GenI.Tag: ts_rootFeatureMismatch :: Flist GeniVal -> String
+ NLP.GenI.Tag: ts_semIncomplete :: [Literal GeniVal] -> String
+ NLP.GenI.Tag: ts_synIncomplete, ts_tbUnificationFailure :: String
+ NLP.GenI.Tag: tsemantics :: TagElem -> Sem
+ NLP.GenI.Tag: tsempols :: TagElem -> [SemPols]
+ NLP.GenI.Tag: ttrace :: TagElem -> [Text]
+ NLP.GenI.Tag: ttree :: TagElem -> Tree (GNode GeniVal)
+ NLP.GenI.Tag: ttreename :: TagElem -> Text
+ NLP.GenI.Tag: ttype :: TagElem -> Ptype
+ NLP.GenI.Tag: type TagDerivation = [DerivationStep]
+ NLP.GenI.Tag: type Tags = Map String [TagElem]
+ NLP.GenI.TestSuite: TestCase :: Text -> Text -> SemInput -> [Text] -> TestCase
+ NLP.GenI.TestSuite: data TestCase
+ NLP.GenI.TestSuite: instance GeniShow TestCase
+ NLP.GenI.TestSuite: instance Pretty TestCase
+ NLP.GenI.TestSuite: tcExpected :: TestCase -> [Text]
+ NLP.GenI.TestSuite: tcName :: TestCase -> Text
+ NLP.GenI.TestSuite: tcSem :: TestCase -> SemInput
+ NLP.GenI.TestSuite: tcSemString :: TestCase -> Text
+ NLP.GenI.TreeSchema: Auxiliar :: Ptype
+ NLP.GenI.TreeSchema: Foot :: GType
+ NLP.GenI.TreeSchema: GN :: NodeName -> Flist gv -> Flist gv -> Bool -> [Text] -> GType -> Bool -> Text -> GNode gv
+ NLP.GenI.TreeSchema: Initial :: Ptype
+ NLP.GenI.TreeSchema: Lex :: GType
+ NLP.GenI.TreeSchema: Other :: GType
+ NLP.GenI.TreeSchema: Subs :: GType
+ NLP.GenI.TreeSchema: TT :: [GeniVal] -> Text -> Text -> Flist GeniVal -> Ptype -> Maybe Sem -> [Text] -> Tree a -> Ttree a
+ NLP.GenI.TreeSchema: crushGNode :: GNode [GeniVal] -> Maybe (GNode GeniVal)
+ NLP.GenI.TreeSchema: crushTreeGNode :: Tree (GNode [GeniVal]) -> Maybe (Tree (GNode GeniVal))
+ NLP.GenI.TreeSchema: data GNode gv
+ NLP.GenI.TreeSchema: data GType
+ NLP.GenI.TreeSchema: data Ptype
+ NLP.GenI.TreeSchema: data Ttree a
+ NLP.GenI.TreeSchema: foot :: Tree (GNode a) -> GNode a
+ NLP.GenI.TreeSchema: gCategory :: Flist GeniVal -> Maybe GeniVal
+ NLP.GenI.TreeSchema: gaconstr :: GNode gv -> Bool
+ NLP.GenI.TreeSchema: ganchor :: GNode gv -> Bool
+ NLP.GenI.TreeSchema: gdown :: GNode gv -> Flist gv
+ NLP.GenI.TreeSchema: glexeme :: GNode gv -> [Text]
+ NLP.GenI.TreeSchema: gnname :: GNode gv -> NodeName
+ NLP.GenI.TreeSchema: gnnameIs :: NodeName -> GNode gv -> Bool
+ NLP.GenI.TreeSchema: gorigin :: GNode gv -> Text
+ NLP.GenI.TreeSchema: gtype :: GNode gv -> GType
+ NLP.GenI.TreeSchema: gup :: GNode gv -> Flist gv
+ NLP.GenI.TreeSchema: instance [overlap ok] Binary GType
+ NLP.GenI.TreeSchema: instance [overlap ok] Binary Ptype
+ NLP.GenI.TreeSchema: instance [overlap ok] Binary a => Binary (Ttree a)
+ NLP.GenI.TreeSchema: instance [overlap ok] Binary gv => Binary (GNode gv)
+ NLP.GenI.TreeSchema: instance [overlap ok] Collectable a => Collectable (Tree a)
+ NLP.GenI.TreeSchema: instance [overlap ok] Collectable a => Collectable (Ttree a)
+ NLP.GenI.TreeSchema: instance [overlap ok] Collectable gv => Collectable (GNode gv)
+ NLP.GenI.TreeSchema: instance [overlap ok] Data GType
+ NLP.GenI.TreeSchema: instance [overlap ok] Data Ptype
+ NLP.GenI.TreeSchema: instance [overlap ok] Data a => Data (Ttree a)
+ NLP.GenI.TreeSchema: instance [overlap ok] Data gv => Data (GNode gv)
+ NLP.GenI.TreeSchema: instance [overlap ok] DescendGeniVal a => DescendGeniVal (Map k a)
+ NLP.GenI.TreeSchema: instance [overlap ok] DescendGeniVal v => DescendGeniVal (GNode v)
+ NLP.GenI.TreeSchema: instance [overlap ok] DescendGeniVal v => DescendGeniVal (Ttree v)
+ NLP.GenI.TreeSchema: instance [overlap ok] Eq GType
+ NLP.GenI.TreeSchema: instance [overlap ok] Eq Ptype
+ NLP.GenI.TreeSchema: instance [overlap ok] Eq a => Eq (Ttree a)
+ NLP.GenI.TreeSchema: instance [overlap ok] Eq gv => Eq (GNode gv)
+ NLP.GenI.TreeSchema: instance [overlap ok] GeniShow (GNode GeniVal)
+ NLP.GenI.TreeSchema: instance [overlap ok] GeniShow Ptype
+ NLP.GenI.TreeSchema: instance [overlap ok] GeniShow a => GeniShow (Ttree a)
+ NLP.GenI.TreeSchema: instance [overlap ok] NFData GType
+ NLP.GenI.TreeSchema: instance [overlap ok] NFData Ptype
+ NLP.GenI.TreeSchema: instance [overlap ok] NFData gv => NFData (GNode gv)
+ NLP.GenI.TreeSchema: instance [overlap ok] Pretty (GNode GeniVal)
+ NLP.GenI.TreeSchema: instance [overlap ok] Show GType
+ NLP.GenI.TreeSchema: instance [overlap ok] Show Ptype
+ NLP.GenI.TreeSchema: instance [overlap ok] Typeable GType
+ NLP.GenI.TreeSchema: instance [overlap ok] Typeable Ptype
+ NLP.GenI.TreeSchema: instance [overlap ok] Typeable1 GNode
+ NLP.GenI.TreeSchema: instance [overlap ok] Typeable1 Ttree
+ NLP.GenI.TreeSchema: lexemeAttributes :: [Text]
+ NLP.GenI.TreeSchema: params :: Ttree a -> [GeniVal]
+ NLP.GenI.TreeSchema: pfamily :: Ttree a -> Text
+ NLP.GenI.TreeSchema: pidname :: Ttree a -> Text
+ NLP.GenI.TreeSchema: pinterface :: Ttree a -> Flist GeniVal
+ NLP.GenI.TreeSchema: psemantics :: Ttree a -> Maybe Sem
+ NLP.GenI.TreeSchema: ptrace :: Ttree a -> [Text]
+ NLP.GenI.TreeSchema: ptype :: Ttree a -> Ptype
+ NLP.GenI.TreeSchema: root :: Tree a -> a
+ NLP.GenI.TreeSchema: rootUpd :: Tree a -> a -> Tree a
+ NLP.GenI.TreeSchema: setAnchor :: FullList Text -> Tree (GNode a) -> Tree (GNode a)
+ NLP.GenI.TreeSchema: setLexeme :: [Text] -> Tree (GNode a) -> Tree (GNode a)
+ NLP.GenI.TreeSchema: showLexeme :: [Text] -> Text
+ NLP.GenI.TreeSchema: tree :: Ttree a -> Tree a
+ NLP.GenI.TreeSchema: type Macros = [SchemaTree]
+ NLP.GenI.TreeSchema: type NodeName = Text
+ NLP.GenI.TreeSchema: type SchemaNode = GNode [GeniVal]
+ NLP.GenI.TreeSchema: type SchemaTree = Ttree SchemaNode
+ NLP.GenI.Warning: CustomLexWarning :: Text -> GeniWarning
+ NLP.GenI.Warning: LexCombineAllSchemataFailed :: LexWarning
+ NLP.GenI.Warning: LexCombineOneSchemaFailed :: LexCombineError -> LexWarning
+ NLP.GenI.Warning: LexWarning :: [LexEntry] -> LexWarning -> GeniWarning
+ NLP.GenI.Warning: MissingCoanchors :: Text -> Int -> LexWarning
+ NLP.GenI.Warning: MorphWarning :: [Text] -> GeniWarning
+ NLP.GenI.Warning: NoLexSelection :: [Literal GeniVal] -> GeniWarning
+ NLP.GenI.Warning: data GeniWarning
+ NLP.GenI.Warning: data GeniWarnings
+ NLP.GenI.Warning: data LexWarning
+ NLP.GenI.Warning: fromGeniWarnings :: GeniWarnings -> [GeniWarning]
+ NLP.GenI.Warning: mkGeniWarnings :: [GeniWarning] -> GeniWarnings
+ NLP.GenI.Warning: showGeniWarning :: GeniWarning -> [Text]
+ NLP.GenI.Warning: sortWarnings :: GeniWarnings -> GeniWarnings
+ NLP.GenI.Warning.Internal: CustomLexWarning :: Text -> GeniWarning
+ NLP.GenI.Warning.Internal: GeniWarnings :: [GeniWarning] -> GeniWarnings
+ NLP.GenI.Warning.Internal: LexCombineAllSchemataFailed :: LexWarning
+ NLP.GenI.Warning.Internal: LexCombineOneSchemaFailed :: LexCombineError -> LexWarning
+ NLP.GenI.Warning.Internal: LexWarning :: [LexEntry] -> LexWarning -> GeniWarning
+ NLP.GenI.Warning.Internal: MissingCoanchors :: Text -> Int -> LexWarning
+ NLP.GenI.Warning.Internal: MorphWarning :: [Text] -> GeniWarning
+ NLP.GenI.Warning.Internal: NoLexSelection :: [Literal GeniVal] -> GeniWarning
+ NLP.GenI.Warning.Internal: appendWarning :: GeniWarning -> [GeniWarning] -> [GeniWarning]
+ NLP.GenI.Warning.Internal: data GeniWarning
+ NLP.GenI.Warning.Internal: data LexWarning
+ NLP.GenI.Warning.Internal: fromGeniWarnings :: GeniWarnings -> [GeniWarning]
+ NLP.GenI.Warning.Internal: instance Eq GeniWarning
+ NLP.GenI.Warning.Internal: instance Eq LexWarning
+ NLP.GenI.Warning.Internal: instance Monoid GeniWarnings
+ NLP.GenI.Warning.Internal: instance Poset GeniWarning
+ NLP.GenI.Warning.Internal: instance Poset LexWarning
+ NLP.GenI.Warning.Internal: mergeWarning :: GeniWarning -> GeniWarning -> Maybe GeniWarning
+ NLP.GenI.Warning.Internal: mkGeniWarnings :: [GeniWarning] -> GeniWarnings
+ NLP.GenI.Warning.Internal: newtype GeniWarnings
+ NLP.GenI.Warning.Internal: posort :: Poset a => [a] -> [a]
+ NLP.GenI.Warning.Internal: showGeniWarning :: GeniWarning -> [Text]
+ NLP.GenI.Warning.Internal: sortWarnings :: GeniWarnings -> GeniWarnings
+ NLP.GenI.Warning.Internal: toWfCount :: [LexEntry] -> WordFamilyCount
+ NLP.GenI.Warning.Internal: type WordFamilyCount = Map (FullList Text, Text) Int
- NLP.GenI.Builder: (>-->) :: (Monad s) => DispatchFilter s a -> DispatchFilter s a -> DispatchFilter s a
+ NLP.GenI.Builder: (>-->) :: Monad s => DispatchFilter s a -> DispatchFilter s a -> DispatchFilter s a
- NLP.GenI.Builder: Builder :: (Input -> pa -> (st, Statistics)) -> BuilderState st () -> BuilderState st () -> (st -> Bool) -> (st -> [Output]) -> (st -> [Output]) -> Builder st it pa
+ NLP.GenI.Builder: Builder :: (Input -> pa -> (st, Statistics)) -> BuilderState st () -> BuilderState st () -> (st -> GenStatus) -> (st -> [Output]) -> (st -> [Output]) -> Builder st it pa
- NLP.GenI.Builder: Input :: SemInput -> [ILexEntry] -> [(TagElem, BitVector)] -> Input
+ NLP.GenI.Builder: Input :: SemInput -> [LexEntry] -> [(TagElem, BitVector)] -> Input
- NLP.GenI.Builder: UninflectedDisjunction :: [String] -> Flist -> UninflectedDisjunction
+ NLP.GenI.Builder: UninflectedDisjunction :: [Text] -> (Flist GeniVal) -> UninflectedDisjunction
- NLP.GenI.Builder: condFilter :: (Monad s) => (a -> Bool) -> DispatchFilter s a -> DispatchFilter s a -> DispatchFilter s a
+ NLP.GenI.Builder: condFilter :: Monad s => (a -> Bool) -> DispatchFilter s a -> DispatchFilter s a -> DispatchFilter s a
- NLP.GenI.Builder: finished :: Builder st it pa -> st -> Bool
+ NLP.GenI.Builder: finished :: Builder st it pa -> st -> GenStatus
- NLP.GenI.Builder: inLex :: Input -> [ILexEntry]
+ NLP.GenI.Builder: inLex :: Input -> [LexEntry]
- NLP.GenI.Builder: lexicalSelection :: Derivation -> [String]
+ NLP.GenI.Builder: lexicalSelection :: TagDerivation -> [Text]
- NLP.GenI.Builder: preInit :: Input -> Params -> (Input, (Int, Int, Int), PolResult)
+ NLP.GenI.Builder: preInit :: Input -> Params -> (Input, PolResult)
- NLP.GenI.Builder: type DispatchFilter s a = a -> s (Maybe a)
+ NLP.GenI.Builder: type DispatchFilter s a = a -> s (FilterStatus a)
- NLP.GenI.Builder: type Output = (LemmaPlusSentence, Derivation)
+ NLP.GenI.Builder: type Output = (Integer, LemmaPlusSentence, TagDerivation)
- NLP.GenI.Builder: type SemBitMap = Map Pred BitVector
+ NLP.GenI.Builder: type SemBitMap = Map (Literal GeniVal) BitVector
- NLP.GenI.Configuration: getFlagP :: (Show f, Show x, Typeable f, Typeable x) => (x -> f) -> Params -> Maybe x
+ NLP.GenI.Configuration: getFlagP :: (Typeable f, Typeable x) => (x -> f) -> Params -> Maybe x
- NLP.GenI.Configuration: getListFlagP :: (Show f, Show x, Typeable f, Typeable x) => ([x] -> f) -> Params -> [x]
+ NLP.GenI.Configuration: getListFlagP :: (Typeable f, Typeable x) => ([x] -> f) -> Params -> [x]
- NLP.GenI.Configuration: noArg :: (Eq f, Show f, Typeable f) => (() -> f) -> ArgDescr Flag
+ NLP.GenI.Configuration: noArg :: (Eq f, Typeable f) => (() -> f) -> ArgDescr Flag
- NLP.GenI.Configuration: optArg :: (Eq f, Show f, Typeable f, Eq x, Show x, Typeable x) => (x -> f) -> x -> (String -> x) -> String -> ArgDescr Flag
+ NLP.GenI.Configuration: optArg :: (Eq f, Typeable f, Eq x, Typeable x) => (x -> f) -> x -> (String -> x) -> String -> ArgDescr Flag
- NLP.GenI.Configuration: reqArg :: (Eq f, Show f, Typeable f, Eq x, Show x, Typeable x) => (x -> f) -> (String -> x) -> String -> ArgDescr Flag
+ NLP.GenI.Configuration: reqArg :: (Eq f, Typeable f, Eq x, Typeable x) => (x -> f) -> (String -> x) -> String -> ArgDescr Flag
- NLP.GenI.Configuration: setFlagP :: (Eq f, Show f, Show x, Typeable f, Typeable x) => (x -> f) -> x -> Params -> Params
+ NLP.GenI.Configuration: setFlagP :: (Eq f, Typeable f, Typeable x) => (x -> f) -> x -> Params -> Params
- NLP.GenI.General: groupByFM :: (Ord b) => (a -> b) -> [a] -> (Map b [a])
+ NLP.GenI.General: groupByFM :: Ord b => (a -> b) -> [a] -> (Map b [a])
- NLP.GenI.General: insertToListMap :: (Ord b) => b -> a -> Map b [a] -> Map b [a]
+ NLP.GenI.General: insertToListMap :: Ord b => b -> a -> Map b [a] -> Map b [a]
- NLP.GenI.General: isEmptyIntersect :: (Eq a) => [a] -> [a] -> Bool
+ NLP.GenI.General: isEmptyIntersect :: Eq a => [a] -> [a] -> Bool
- NLP.GenI.General: mapMaybeM :: (Monad m) => (a -> m (Maybe b)) -> [a] -> m [b]
+ NLP.GenI.General: mapMaybeM :: Monad m => (a -> m (Maybe b)) -> [a] -> m [b]
- NLP.GenI.GeniShow: class GeniShow a
+ NLP.GenI.GeniShow: class GeniShow a where geniShow = unpack . geniShowText geniShowText = pack . geniShow
- NLP.GenI.GeniShow: geniShow :: (GeniShow a) => a -> String
+ NLP.GenI.GeniShow: geniShow :: GeniShow a => a -> String
- NLP.GenI.GeniVal: SuccessRep :: String -> GeniVal -> UnificationResult
+ NLP.GenI.GeniVal: SuccessRep :: Text -> GeniVal -> UnificationResult
- NLP.GenI.GeniVal: descendGeniVal :: (DescendGeniVal a) => (GeniVal -> GeniVal) -> a -> a
+ NLP.GenI.GeniVal: descendGeniVal :: DescendGeniVal a => (GeniVal -> GeniVal) -> a -> a
- NLP.GenI.GeniVal: replace :: (DescendGeniVal a) => Subst -> a -> a
+ NLP.GenI.GeniVal: replace :: DescendGeniVal a => Subst -> a -> a
- NLP.GenI.GeniVal: replaceList :: (DescendGeniVal a) => [(String, GeniVal)] -> a -> a
+ NLP.GenI.GeniVal: replaceList :: DescendGeniVal a => [(Text, GeniVal)] -> a -> a
- NLP.GenI.GeniVal: type Subst = Map String GeniVal
+ NLP.GenI.GeniVal: type Subst = Map Text GeniVal
- NLP.GenI.GeniVal: unify :: (Monad m) => [GeniVal] -> [GeniVal] -> m ([GeniVal], Subst)
+ NLP.GenI.GeniVal: unify :: Monad m => [GeniVal] -> [GeniVal] -> m ([GeniVal], Subst)
- NLP.GenI.Morphology: attachMorph :: MorphFn -> Sem -> [TagElem] -> [TagElem]
+ NLP.GenI.Morphology: attachMorph :: MorphInputFn -> Sem -> [TagElem] -> [TagElem]
- NLP.GenI.Morphology: inflectSentencesUsingCmd :: String -> [LemmaPlusSentence] -> IO [(LemmaPlusSentence, [String])]
+ NLP.GenI.Morphology: inflectSentencesUsingCmd :: String -> [LemmaPlusSentence] -> IO [(LemmaPlusSentence, MorphOutput)]
- NLP.GenI.Morphology: readMorph :: [(String, [AvPair])] -> MorphFn
+ NLP.GenI.Morphology: readMorph :: [(Text, [AvPair GeniVal])] -> MorphInputFn
- NLP.GenI.Morphology: sansMorph :: LemmaPlusSentence -> [String]
+ NLP.GenI.Morphology: sansMorph :: LemmaPlusSentence -> MorphOutput
- NLP.GenI.Morphology: setMorphAnchor :: GNode -> Tree GNode -> Tree GNode
+ NLP.GenI.Morphology: setMorphAnchor :: GNode GeniVal -> Tree (GNode GeniVal) -> Tree (GNode GeniVal)
- NLP.GenI.Morphology: stripMorphSem :: MorphFn -> Sem -> Sem
+ NLP.GenI.Morphology: stripMorphSem :: MorphInputFn -> Sem -> Sem
- NLP.GenI.OptimalityTheory: NegativeC :: String -> OtConstraint
+ NLP.GenI.OptimalityTheory: NegativeC :: Text -> OtConstraint
- NLP.GenI.OptimalityTheory: NegativeConjC :: [String] -> OtConstraint
+ NLP.GenI.OptimalityTheory: NegativeConjC :: [Text] -> OtConstraint
- NLP.GenI.OptimalityTheory: PositiveC :: String -> OtConstraint
+ NLP.GenI.OptimalityTheory: PositiveC :: Text -> OtConstraint
- NLP.GenI.OptimalityTheory: otWarnings :: Macros -> OtRanking -> [OtViolation] -> [String]
+ NLP.GenI.OptimalityTheory: otWarnings :: Macros -> OtRanking -> [OtViolation] -> [Text]
- NLP.GenI.OptimalityTheory: prettyRank :: Int -> String
+ NLP.GenI.OptimalityTheory: prettyRank :: Int -> Text
- NLP.GenI.OptimalityTheory: prettyViolations :: GetTraces -> Bool -> [OtViolation] -> String
+ NLP.GenI.OptimalityTheory: prettyViolations :: GetTraces -> Bool -> [OtViolation] -> Text
- NLP.GenI.OptimalityTheory: rankResults :: GetTraces -> (a -> Derivation) -> OtRanking -> [a] -> [OtResult a]
+ NLP.GenI.OptimalityTheory: rankResults :: GetTraces -> (a -> TagDerivation) -> OtRanking -> [a] -> [OtResult a]
- NLP.GenI.OptimalityTheory: type GetTraces = String -> [String]
+ NLP.GenI.OptimalityTheory: type GetTraces = Text -> [Text]
- NLP.GenI.Polarity: PolSt :: Int -> [Pred] -> [(Int, Int)] -> PolState
+ NLP.GenI.Polarity: PolSt :: Int -> [Literal GeniVal] -> [(Int, Int)] -> PolState
- NLP.GenI.Polarity: buildAutomaton :: Set PolarityAttr -> Flist -> PolMap -> SemInput -> [TagElem] -> PolResult
+ NLP.GenI.Polarity: buildAutomaton :: Set PolarityAttr -> FeatStruct GeniVal -> PolMap -> SemInput -> [TagElem] -> PolResult
- NLP.GenI.Polarity: declareIdxConstraints :: Flist -> PolMap
+ NLP.GenI.Polarity: declareIdxConstraints :: Flist GeniVal -> PolMap
- NLP.GenI.Polarity: detectIdxConstraints :: Flist -> Flist -> PolMap
+ NLP.GenI.Polarity: detectIdxConstraints :: Flist GeniVal -> Flist GeniVal -> PolMap
- NLP.GenI.Polarity: detectPols :: Set PolarityAttr -> [TagElem] -> [TagElem]
+ NLP.GenI.Polarity: detectPols :: Set PolarityAttr -> TagElem -> TagElem
- NLP.GenI.Polarity: makePolAut :: [TagElem] -> Sem -> PolMap -> PolResult
+ NLP.GenI.Polarity: makePolAut :: [TagElem] -> Sem -> PolMap -> [PolarityKey] -> PolResult
- NLP.GenI.Simple.SimpleBuilder: SimpleGuiItem :: [String] -> [GNode] -> [String] -> Sem -> String -> SimpleGuiItem
+ NLP.GenI.Simple.SimpleBuilder: SimpleGuiItem :: [Text] -> [String] -> Sem -> Text -> SimpleGuiItem
- NLP.GenI.Simple.SimpleBuilder: SimpleItem :: ChartId -> [TagSite] -> [TagSite] -> BitVector -> BitVector -> [String] -> [String] -> [(String, UninflectedDisjunction)] -> Tree String -> TagSite -> Maybe TagSite -> [TagSite] -> TagDerivation -> SimpleGuiItem -> SimpleItem
+ NLP.GenI.Simple.SimpleBuilder: SimpleItem :: ChartId -> [NodeName] -> [NodeName] -> BitVector -> BitVector -> [GNode GeniVal] -> Tree Text -> NodeName -> Maybe NodeName -> [NodeName] -> TagDerivation -> SimpleGuiItem -> SimpleItem
- NLP.GenI.Simple.SimpleBuilder: siAdjnodes :: SimpleItem -> [TagSite]
+ NLP.GenI.Simple.SimpleBuilder: siAdjnodes :: SimpleItem -> [NodeName]
- NLP.GenI.Simple.SimpleBuilder: siDerived :: SimpleItem -> Tree String
+ NLP.GenI.Simple.SimpleBuilder: siDerived :: SimpleItem -> Tree Text
- NLP.GenI.Simple.SimpleBuilder: siHighlight :: SimpleGuiItem -> [String]
+ NLP.GenI.Simple.SimpleBuilder: siHighlight :: SimpleGuiItem -> [Text]
- NLP.GenI.Simple.SimpleBuilder: siIdname :: SimpleGuiItem -> String
+ NLP.GenI.Simple.SimpleBuilder: siIdname :: SimpleGuiItem -> Text
- NLP.GenI.Simple.SimpleBuilder: siNodes :: SimpleGuiItem -> [GNode]
+ NLP.GenI.Simple.SimpleBuilder: siNodes :: SimpleItem -> [GNode GeniVal]
- NLP.GenI.Simple.SimpleBuilder: siPendingTb :: SimpleItem -> [TagSite]
+ NLP.GenI.Simple.SimpleBuilder: siPendingTb :: SimpleItem -> [NodeName]
- NLP.GenI.Simple.SimpleBuilder: siSubstnodes :: SimpleItem -> [TagSite]
+ NLP.GenI.Simple.SimpleBuilder: siSubstnodes :: SimpleItem -> [NodeName]
- NLP.GenI.Statistics: initialStatisticsStateFor :: (MonadState Statistics m) => (m a -> Statistics -> b) -> m a -> b
+ NLP.GenI.Statistics: initialStatisticsStateFor :: MonadState Statistics m => (m a -> Statistics -> b) -> m a -> b
- NLP.GenI.Statistics: type StatisticsState a = forall m. (MonadState Statistics m) => m a
+ NLP.GenI.Statistics: type StatisticsState a = forall m. MonadState Statistics m => m a
Files
- GenI.cabal +98/−68
- INSTALL +4/−5
- NEWS +108/−0
- README +17/−14
- Setup.hs +1/−116
- etc/macstuff/Info.plist +0/−36
- etc/macstuff/wxmac.icns binary
- etc/stupidmorph.pl +0/−85
- examples/artificial/lexicon +8/−0
- examples/artificial/macros +0/−126
- examples/artificial/suite +5/−0
- examples/artificial/suite-bad +2/−0
- examples/artificial/trees +150/−0
- examples/chatnoir/macros +0/−132
- examples/chatnoir/trees +132/−0
- examples/demo/macros +0/−439
- examples/demo/trees +439/−0
- examples/ej/lexicon +4/−0
- examples/ej/macros +0/−92
- examples/ej/suite +6/−0
- examples/ej/trees +92/−0
- examples/nosemantics/macros +0/−363
- examples/nosemantics/trees +363/−0
- examples/promettre/macros +0/−450
- examples/promettre/trees +450/−0
- examples/xmg-example/Makefile +4/−8
- geni-test/MainTest.hs +5/−0
- geni-test/NLP/GenI/Test.hs +53/−0
- geni/geni.hs +20/−0
- src/BoolExp.hs +12/−0
- src/Data/FullList.hs +14/−0
- src/Data/FullList/Internal.hs +80/−0
- src/MainGeni.lhs +0/−126
- src/NLP/GenI.hs +872/−0
- src/NLP/GenI/Btypes.lhs +0/−757
- src/NLP/GenI/BtypesBinary.hs +0/−59
- src/NLP/GenI/Builder.hs +404/−0
- src/NLP/GenI/Builder.lhs +0/−562
- src/NLP/GenI/BuilderGui.lhs +0/−34
- src/NLP/GenI/Configuration.hs +735/−0
- src/NLP/GenI/Configuration.lhs +0/−891
- src/NLP/GenI/Console.hs +208/−119
- src/NLP/GenI/FeatureStructure.hs +186/−0
- src/NLP/GenI/Flag.hs +146/−0
- src/NLP/GenI/General.hs +104/−120
- src/NLP/GenI/Geni.lhs +0/−1149
- src/NLP/GenI/GeniParsers.lhs +0/−919
- src/NLP/GenI/GeniShow.hs +36/−138
- src/NLP/GenI/GeniVal.hs +26/−289
- src/NLP/GenI/GeniVal/Internal.hs +428/−0
- src/NLP/GenI/Graphviz.hs +0/−214
- src/NLP/GenI/GraphvizShow.hs +0/−199
- src/NLP/GenI/GraphvizShowPolarity.lhs +0/−130
- src/NLP/GenI/Gui.lhs +0/−778
- src/NLP/GenI/GuiHelper.hs +0/−750
- src/NLP/GenI/LexicalSelection.hs +425/−0
- src/NLP/GenI/LexicalSelection/Types.hs +149/−0
- src/NLP/GenI/Lexicon.hs +27/−0
- src/NLP/GenI/Lexicon/Internal.hs +203/−0
- src/NLP/GenI/Main.hs +58/−0
- src/NLP/GenI/Morphology.hs +218/−0
- src/NLP/GenI/Morphology.lhs +0/−233
- src/NLP/GenI/Morphology/Types.hs +104/−0
- src/NLP/GenI/OptimalityTheory.hs +343/−0
- src/NLP/GenI/OptimalityTheory.lhs +0/−390
- src/NLP/GenI/Parser.hs +633/−0
- src/NLP/GenI/Polarity.hs +572/−0
- src/NLP/GenI/Polarity.lhs +0/−1206
- src/NLP/GenI/Polarity/Internal.hs +190/−0
- src/NLP/GenI/Polarity/Types.hs +84/−0
- src/NLP/GenI/PolarityTypes.hs +0/−44
- src/NLP/GenI/Pretty.hs +88/−0
- src/NLP/GenI/Regression.hs +0/−83
- src/NLP/GenI/Semantics.hs +267/−0
- src/NLP/GenI/Simple/SimpleBuilder.hs +937/−0
- src/NLP/GenI/Simple/SimpleBuilder.lhs +0/−1225
- src/NLP/GenI/Simple/SimpleGui.lhs +0/−208
- src/NLP/GenI/Statistics.hs +20/−2
- src/NLP/GenI/SysGeni.hs +0/−77
- src/NLP/GenI/Tag.hs +396/−0
- src/NLP/GenI/Tags.lhs +0/−380
- src/NLP/GenI/Test.hs +0/−31
- src/NLP/GenI/TestSuite.hs +46/−0
- src/NLP/GenI/TreeSchema.hs +351/−0
- src/NLP/GenI/Warning.hs +32/−0
- src/NLP/GenI/Warning/Internal.hs +146/−0
GenI.cabal view
@@ -1,5 +1,5 @@ Name: GenI-Version: 0.20.2+Version: 0.22 License: GPL License-file: LICENSE Author: Carlos Areces and Eric Kow@@ -8,28 +8,28 @@ Description: A natural language generator (specifically, an FB-LTAG surface realiser) Homepage: http://projects.haskell.org/GenI Maintainer: geni-users@loria.fr-Build-Type: Custom-Cabal-Version: >=1.2.3+Build-Type: Simple+Cabal-Version: >=1.8 data-files: AUTHORS, INSTALL, README, NEWS, GenI.cabal, examples/artificial/lexicon,- examples/artificial/macros,+ examples/artificial/trees, examples/artificial/suite, examples/artificial/suite-bad, examples/chatnoir/lexicon,- examples/chatnoir/macros,+ examples/chatnoir/trees, examples/chatnoir/suite, examples/demo/lexicon,- examples/demo/macros,+ examples/demo/trees, examples/demo/README, examples/demo/suite, examples/ej/lexicon,- examples/ej/macros,+ examples/ej/trees, examples/ej/suite, examples/nosemantics/lexicon,- examples/nosemantics/macros,+ examples/nosemantics/trees, examples/nosemantics/README.txt, examples/promettre/lexicon,- examples/promettre/macros,+ examples/promettre/trees, examples/promettre/morphinfo, examples/promettre/suite, examples/xmg-example/grammar/Arguments.mg,@@ -44,93 +44,123 @@ examples/xmg-example/lexicon/demo-morph-utf8.mph, examples/xmg-example/Makefile, examples/xmg-example/README,- examples/xmg-example/suite,- etc/stupidmorph.pl,- etc/macstuff/Info.plist,- etc/macstuff/wxmac.icns--extra-source-files: src/NLP/GenI/SysGeni.hs- src/NLP/GenI/Test.hs- src/NLP/GenI/Simple/SimpleGui.lhs,- src/NLP/GenI/Gui.lhs- src/NLP/GenI/GraphvizShow.hs,- src/NLP/GenI/GuiHelper.hs- src/NLP/GenI/Console.hs,- src/NLP/GenI/Graphviz.hs- src/NLP/GenI/BuilderGui.lhs,- src/NLP/GenI/GraphvizShowPolarity.lhs,- src/NLP/GenI/Regression.hs+ examples/xmg-example/suite +extra-source-files: geni-test/NLP/GenI/Test.hs -Flag gui- description: Build with a graphical user interface- default: False+source-repository head+ type: darcs+ location: http://code.haskell.org/GenI Flag static Description: Build a static binary Default: False Library- Build-depends: parsec >= 2 && < 3,- base >= 3 && < 4,- containers >= 0.1,- process > 1,- QuickCheck >= 1.2 && < 2,- json >= 0.4.3 && < 0.5,- HUnit > 1 && < 1.3,- mtl > 1.0 && < 1.2,- parallel >= 1.1 && < 1.2,- binary >= 0.5.0.2 && < 0.6,- split >= 0.1.1 && < 0.2,- test-framework-hunit >= 0.2.4 && < 0.3,- test-framework-quickcheck >= 0.2.4 && < 0.3,- test-framework >= 0.2.4 && < 0.3,- utf8-string >= 0.3.5 && < 0.4,- uniplate >= 1.2.0 && < 1.3-- if !flag(gui)- cpp-options: -DDISABLE_GUI+ Build-depends: base >= 4 && < 5+ , binary >= 0.5.0.2+ , bytestring == 0.9.*+ , cabal-macosx >= 0.1.2 && < 0.3+ , containers >= 0.1+ , deepseq+ , directory > 1+ , filepath == 1.*+ , hslogger == 1.1.*+ , json >= 0.4.3 && < 0.6+ , MaybeT == 0.1.*+ , mtl > 1.0 && < 2.1+ , old-locale+ , ordered == 0.1.*+ , parsec >= 2 && < 3.2+ , process > 1+ , split >= 0.1.1 && < 0.2+ , syb+ , text+ , time >= 1.1 && < 1.3+ , utf8-string >= 0.3.5 && < 0.4+ , yaml-light == 0.1.* if flag(static) ghc-options: -static -optl-static Exposed-Modules:- NLP.GenI.Btypes,- NLP.GenI.BtypesBinary,+ BoolExp,+ Data.FullList.Internal,+ Data.FullList,+ NLP.GenI.Console,+ NLP.GenI.FeatureStructure,+ NLP.GenI.Flag, NLP.GenI.General,- NLP.GenI.GeniParsers, NLP.GenI.GeniShow, NLP.GenI.GeniVal,- NLP.GenI.Tags,+ NLP.GenI.GeniVal.Internal,+ NLP.GenI.Lexicon,+ NLP.GenI.Lexicon.Internal,+ NLP.GenI.LexicalSelection,+ NLP.GenI.LexicalSelection.Types,+ NLP.GenI.Main,+ NLP.GenI.Parser,+ NLP.GenI.Pretty,+ NLP.GenI.Semantics,+ NLP.GenI.Tag,+ NLP.GenI.TestSuite,+ NLP.GenI.TreeSchema,+ NLP.GenI.Warning,+ NLP.GenI.Warning.Internal, NLP.GenI.Morphology,+ NLP.GenI.Morphology.Types, NLP.GenI.OptimalityTheory, NLP.GenI.Polarity,- NLP.GenI.PolarityTypes,+ NLP.GenI.Polarity.Internal,+ NLP.GenI.Polarity.Types, NLP.GenI.Automaton, NLP.GenI.Statistics, NLP.GenI.Builder, NLP.GenI.Simple.SimpleBuilder,- -- NLP.GenI.CkyEarley.CkyBuilder,- NLP.GenI.Geni, NLP.GenI.Configuration+ NLP.GenI.Configuration,+ NLP.GenI+ Other-Modules:+ Paths_GenI Hs-Source-Dirs: src- Extensions: CPP, Rank2Types, OverlappingInstances, MultiParamTypeClasses, FlexibleContexts, TypeSynonymInstances, FlexibleInstances, DeriveDataTypeable, ExistentialQuantification, LiberalTypeSynonyms- Ghc-options: -Wall -O2+ Ghc-options: -Wall Ghc-prof-options: -auto-all Executable geni- Main-Is: MainGeni.lhs- Hs-Source-Dirs: src- Extensions: CPP, Rank2Types, OverlappingInstances, MultiParamTypeClasses, FlexibleContexts, TypeSynonymInstances, FlexibleInstances, DeriveDataTypeable, ExistentialQuantification, LiberalTypeSynonyms+ Main-Is: geni.hs+ Hs-Source-Dirs: geni - Ghc-options: -Wall -O2+ Ghc-options: -Wall -rtsopts Ghc-prof-options: -auto-all- Build-Depends: directory > 1,- filepath >= 1.1.0 && < 1.2- if flag(gui)- Build-Depends: wx >= 0.10.3 && < 0.13- else- cpp-options: -DDISABLE_GUI+ Build-Depends: base >= 4 && < 5+ , GenI+ , containers >= 0.1+ , directory > 1+ , filepath == 1.*+ , yaml-light == 0.1.*+ , hslogger == 1.1.*+ , json >= 0.4 && < 0.6+ , mtl > 1.0 && < 2.1+ , process > 1+ , split == 0.1.*+ , utf8-string == 0.3.* - if flag(static)- ghc-options: -static -optl-static+Test-Suite geni-test+ Type: exitcode-stdio-1.0+ Main-Is: MainTest.hs+ Hs-Source-Dirs: geni-test+ Build-Depends: GenI+ , base >= 4 && < 5+ , containers >= 0.1+ , filepath == 1.*+ , json+ , mtl+ , parsec >= 2 && < 3.2+ , QuickCheck == 2.4.*+ , smallcheck+ , HUnit > 1 && < 1.3+ , test-framework-hunit >= 0.2.4 && < 0.3+ , test-framework-quickcheck2 >= 0.2.4 && < 0.3+ , test-framework-smallcheck+ , test-framework > 0.3+ , text
INSTALL view
@@ -1,13 +1,12 @@ Requirements ------------- * GHC 6.8 or 6.10- * libgmp (for ghc)+ * Haskell Platform 2011.3.0.0 GUI requirements ---------------- Only needed if you want the graphical interface: * wxWidgets 2.8- * wxHaskell 0.11+ * wxHaskell * Graphviz Building GenI@@ -15,7 +14,7 @@ 1. obtain cabal-install 2. run: cabal install 3. if you want the graphical interface, try- cabal install -fgui+ cabal install ./geni-gui but ONLY AFTER you succeed in installing the text version :-) -For more details, see http://trac.haskell.org/GenI+For more details, see http://projects.haskell.org/GenI
NEWS view
@@ -1,3 +1,111 @@+GenI 0.22, 14 Apr 2012+----------------------+Note that the changes between this release and 0.20 are considered to be under+the BSD3 license. GenI overall remains dual-licensed under the GPL and any+commercial-use terms you may wish to negotiate with INRIA. Having secured the+rights to use GenI 0.20, you may freely use GenI 0.22 in a similar fashion.++CHANGES TO WATCH OUT FOR++* Separation of geni and geni-gui into two packages;+ simpler installation+* Now using the top feature for lemanchors instead of bot+* Empty disjunctions forbidden in unification variables+* JSON input/output to morph processors have changed+* Lexical selection unifies semantics of tree schema + lemma with+ input semantics.++GUI++* New results tab with reminder of inputs+* Add gui element to display unanchored lexical selection.+* Jump to new tab in debugger panel when created.+* Update gui to use Pretty instead of Show+* Rename $algo-session tab to "tree assembly"+* Make warnings resizable.+* Fix display of path equations with 'interface' in them.+* Fix #50 - load button has no effect.+* Fix #49 - correct order that leaf nodes are returned.+* Show GenI version in About box.+* Add detect polarities and root feature editor to main gui.++DOCUMENTATION++* Literate GenI and genimanual replaced with+ http://projects.haskell.org/GenI/manual++GENERAL++* Builds with GHC 7+* Core behaviour+ * Early null-adjunction and semfilter obligatory+ * Handling of zero-literal semantic items restored+ * Unconstrained polarities in automaton construction.+ This makes it possible to do polarity detection with only a+ weakly specified root feature like [cat:_], and without needing+ the relevant feature to be implemented everywhere.++* Flags:+ * --trees (used to be --macros; latter is deprecated)+ * --batchdir now optional (defaults to a new temp dir)+ * --maxsteps (stop after N steps)+ * --extrapol REMOVED (use root feature instead)+* Logging facility (not used much in GenI yet)+ Can be configured in ~/.geni/config.yaml, for example+ logging:+ -+ name : NLP.GenI.Console+ level : WARN+ format : simple "$msg"+ -+ name : NLP.Geni.LexicalSelection+ level : DEBUG+ format : simple "$utcTime $loggername $msg"+ handler : stderr+* Less repetition in warnings (hopefully easier to read)+* More hiding of constructors for safety+* New enrichment option for setting co-anchors (foo.lex=hello)+* Lexical selection performance enhancements+* Variables that only occur once are converted to anonymous,+ should make unification a bit more efficient+* Fix #39: reject malformed root feature input.+* New feature:+ * Variables with constraints on their possible values (?X/foo|bar)+ * Fancy disjunctions: tree schemata now allow disjunctions of+ unification variables (but not recursive). These must flatten down+ to plain old atomic disjunction once converted to elementary trees++* Time metric in statistics (Laura Perez)+* Do top/bottom unification on na-constrained nodes during initialisation.+* Polarity detection relaxed to work with constrained variables too.+ (?X/foo|bar gives the result as foo|bar)+* Bugfix in interpretation of root feature (it should be sorted).+* Flags:+ * --rootfeat always assumed, but defaults to '[cat:_]'+ * '-r' a short command line option for '--rootfeat'.++LIBRARY++* Somewhat safer and easier to understand API+ (still no stability yet)+* Replace String with Text in GeniVal+* Replace Show abuse with custom Pretty class+* Slightly less stateful (no target semantics in state)+* Much rearranging and renaming (sorry!)+* New: ability to provide custom lexical selection action+* New: ability to provide custom morph postprocessing action+* de-haskell98 (Gwern Branwen)+* No more null builder.++TOOLS (darcs get --lazy http://code.haskell.org/GenI)++* new tool, genireport: summarise batch generation results+* geniserver now talks over HTTP using a JSON format+* Use Sylvain Salvati's xmg2geni.xsl instead of geniconvert.+ * xmg2geni: fix treatment of missing lexemes.+ * xmg2geni: treat type=coanchor as other nodes in GenI.+* geniwrapper: illustrates C wrapper of GenI API+ GenI 0.20, 29 Sep 2009 ---------------------- - NON BACKWARD-COMPATIBLE CHANGES
README view
@@ -1,24 +1,27 @@-documentation+Documentation --------------make doc # (pdflatex and haddock are needed)- 1. users manual: - http://wiki.loria.fr/wiki/GenI-2. semi-literate source code: - doc/genidoc.pdf -3. API: - doc/api/index.html+ http://projects.haskell.org/GenI/manual+2. API:+ http://projects.haskell.org/GenI/api-doc -installing GenI+Installing GenI ----------------(tested on Linux and MacOs X)+(tested on Linux, Windows, and MacOS X) -see INSTALL for details+see INSTALL for details (should just be cabal install) -assuming everything above is installed correctly,-it should possible to just make+Development+-----------+The code style has evolved a lot. Sorry for the inconsistency.+As of 2012-05-06, I'm trying to move to a published style guide+so I can stop thinking about it -contact us!+ https://github.com/tibbe/haskell-style-guide++But the code will take a long time to catch up++Contact us! ----------- Please let us know if you are using GenI; we'd like to hear about your experiences, both positive and negative.
Setup.hs view
@@ -1,117 +1,2 @@-{-# LANGUAGE CPP #-}--import Control.Monad (foldM_, forM_)-import Data.Maybe ( fromMaybe )-import System.Cmd-import System.Exit-import System.Info (os)-import System.FilePath-import System.Directory ( doesFileExist, copyFile, removeFile, createDirectoryIfMissing )--import Distribution.PackageDescription-import Distribution.Simple.Setup import Distribution.Simple-import Distribution.Simple.LocalBuildInfo--#ifndef WIN32-import System.Posix.Files (fileMode, getFileStatus, setFileMode,- ownerExecuteMode, groupExecuteMode, otherExecuteMode)-import Data.Bits ( (.|.) )-#endif--main :: IO ()-main = defaultMainWithHooks $ addMacHook simpleUserHooks- where- addMacHook h =- case os of- "darwin" -> h { postInst = appBundleHook } -- is it OK to treat darwin as synonymous with MacOS X?- _ -> h--appBundleHook :: Args -> InstallFlags -> PackageDescription -> LocalBuildInfo -> IO ()-appBundleHook _ _ pkg localb =- forM_ exes $ \app ->- do createAppBundle theBindir (buildDir localb </> app </> app)- customiseAppBundle (appBundlePath theBindir app) app- `catch` \err -> putStrLn $ "Warning: could not customise bundle for " ++ app ++ ": " ++ show err- removeFile (theBindir </> app)- createAppBundleWrapper theBindir app- where- theBindir = bindir $ absoluteInstallDirs pkg localb NoCopyDest- exes = fromMaybe (map exeName $ executables pkg) mRestrictTo---- ------------------------------------------------------------------------- helper code for application bundles--- -------------------------------------------------------------------------- | 'createAppBundle' @d p@ - creates an application bundle in @d@--- for program @p@, assuming that @d@ already exists and is a directory.--- Note that only the filename part of @p@ is used.-createAppBundle :: FilePath -> FilePath -> IO ()-createAppBundle dir p =- do createDirectoryIfMissing False $ bundle- createDirectoryIfMissing True $ bundleBin- createDirectoryIfMissing True $ bundleRsrc- copyFile p (bundleBin </> takeFileName p)- where- bundle = appBundlePath dir p- bundleBin = bundle </> "Contents/MacOS"- bundleRsrc = bundle </> "Contents/Resources"---- | 'createAppBundleWrapper' @d p@ - creates a script in @d@ that calls--- @p@ from the application bundle @d </> takeFileName p <.> "app"@-createAppBundleWrapper :: FilePath -> FilePath -> IO ()-createAppBundleWrapper bindir p =- do writeFile scriptFile scriptTxt- makeExecutable scriptFile- where- scriptFile = bindir </> takeFileName p- scriptTxt = "`dirname $0`" </> appBundlePath "." p </> "Contents/MacOS" </> takeFileName p ++ " \"$@\""--appBundlePath :: FilePath -> FilePath -> FilePath-appBundlePath dir p = dir </> takeFileName p <.> "app"---- ------------------------------------------------------------------------- utilities--- ------------------------------------------------------------------------makeExecutable :: FilePath -> IO ()-#ifdef WIN32-makeExecutable = const (return ())-#else-makeExecutable f =- do st <- getFileStatus f- let m = fileMode st- m2 = m .|. ownerExecuteMode .|. groupExecuteMode .|. otherExecuteMode- setFileMode f m2-#endif---- ------------------------------------------------------------------------- customisations--- -------------------------------------------------------------------------- | Put here IO actions needed to add any fancy things (eg icons)--- you want to your application bundle.-customiseAppBundle :: FilePath -- ^ app bundle path- -> FilePath -- ^ full path to original binary- -> IO ()-customiseAppBundle bundleDir p =- case takeFileName p of- "geni" ->- do hasRez <- doesFileExist "/Developer/Tools/Rez"- if hasRez- then do -- set the icon- copyFile "etc/macstuff/Info.plist" (bundleDir </> "Contents/Info.plist")- copyFile "etc/macstuff/wxmac.icns" (bundleDir </> "Contents/Resources/wxmac.icns")- -- no idea what this does- system ("/Developer/Tools/Rez -t APPL Carbon.r -o " ++ bundleDir </> "Contents/MacOS/geni")- writeFile (bundleDir </> "PkgInfo") "APPL????"- -- tell Finder about the icon- system ("/Developer/Tools/SetFile -a C " ++ bundleDir </> "Contents")- return ()- else putStrLn "Developer Tools not found. Too bad; no fancy icons for you."- "" -> return ()---- | Put here the list of executables which contain a GUI. If they all--- contain a GUI (or you don't really care that much), just put Nothing-mRestrictTo :: Maybe [String]-mRestrictTo = Just ["geni"]+main = defaultMain
− etc/macstuff/Info.plist
@@ -1,36 +0,0 @@-<?xml version="1.0" encoding="UTF-8"?>-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">-<plist version="1.0">-<dict>- <key>CFBundleDevelopmentRegion</key>- <string>English</string>- <key>CFBundleExecutable</key>- <string>geni</string>- <key>CFBundleGetInfoString</key>- <string>GenI</string>- <key>CFBundleIconFile</key>- <string>wxmac.icns</string>- <key>CFBundleIdentifier</key>- <string>fr.loria.geni</string>- <key>CFBundleInfoDictionaryVersion</key>- <string>6.0</string>- <key>CFBundleLongVersionString</key>- <string>(c) 2005-2009 LORIA</string>- <key>CFBundleName</key>- <string>GenI</string>- <key>CFBundlePackageType</key>- <string>APPL</string>- <key>CFBundleShortVersionString</key>- <string>0</string>- <key>CFBundleSignature</key>- <string>????</string>- <key>CFBundleVersion</key>- <string>0</string>- <key>CSResourcesFileMapped</key>- <true/>- <key>LSRequiresCarbon</key>- <true/>- <key>NSHumanReadableCopyright</key>- <string>Copyright 2005-2009 LORIA</string>-</dict>-</plist>
− etc/macstuff/wxmac.icns
binary file changed (46234 → absent bytes)
− etc/stupidmorph.pl
@@ -1,85 +0,0 @@-:-eval 'exec perl -w -S $0 ${1+"$@"}'- if 0; --use strict;-use JSON;--# ---------------------------------------------------------------------# idiotic morphological generator-#-# this outputs for each lemma the name of the lemma and its category-# ----------------------------------------------------------------------# ---------------------------------------------------------------------# from GenI-# ----------------------------------------------------------------------# we return a list of lists of hashes-# - each item in the outer list corresponds to a sentence-# - each item in the inner list corresponds to a word-# - each hash represents the features read from GenI plus a special "__lemma__" feature-# which holds the lemma-sub read_morph_request {- my $json_str = shift;- my $allR = from_json $json_str;- my @r_sentences = (); # one request per sentence-- foreach my $sentenceR (@$allR) {- my @r_words = ();- foreach my $wordR (@$sentenceR) {- my $lemma = $wordR->{lemma};- my $featstr = $wordR->{"lemma-features"};- $featstr =~ s/^\[//;- $featstr =~ s/\]$//;-- my %feat = ();- my $av = "";- for (split(/ /, $featstr)) {- $av = $_;- my ($attr, $val) = split(/:/,$av);- $feat{$attr} = $val;- }- $feat{"__lemma__"} = $lemma;- push @r_words, \%feat;- }- push @r_sentences, \@r_words;- }- return \@r_sentences-}--# ---------------------------------------------------------------------# morph-# ----------------------------------------------------------------------sub morph {- my $lemma = shift;- my $featsR = shift;- my $cat = $featsR->{"cat"};- return "$lemma:$cat";-}--# ---------------------------------------------------------------------# main-# ----------------------------------------------------------------------# slurp STDIN to $buf (copied from web)-my $holdTerminator = $/;-undef $/;-my $buf = <STDIN>;-$/ = $holdTerminator;--my @output = ();-my $reqsR = read_morph_request $buf;-foreach my $sentenceR (@$reqsR) {- my @output_words = ();- foreach my $wordR (@$sentenceR) {- my $inflected = morph($wordR->{"__lemma__"}, $wordR);- push @output_words, $inflected;- }- my $output_sentence = join(" ",@output_words);- my @singleton = ( $output_sentence );- push @output, \@singleton;-}--print to_json(\@output);
examples/artificial/lexicon view
@@ -46,7 +46,10 @@ tb-unification-noadj tb-unification-noadj () semantics:[tb-unification-noadj()] tb-unification-bot tb-unification-bot () semantics:[tb-unification-bot()] tb-unification-adj tb-unification-adj () semantics:[tb-unification-adj()]+tb-unification-na tb-unification-na(?X) semantics:[tb-unification-na(?X)]+tb-unification-anchor tb-unification-anchor(?X) semantics:[tb-unification-anchor(?X)] + no-thing no-thing () semantics:[no-thing()] thing-good thing-good () semantics:[thing-good()] thing-bad thing-bad () semantics:[thing-bad()]@@ -54,3 +57,8 @@ "string-literal-in-lemma" term () semantics:["string-lit'+!|"(foo)] lemanchor lemanchor() semantics:[lemanchor()]++preterminal preterminal() semantics:[preterminal()]++disjunction disjunction(x y z) semantics:[disjunction()]+variablecat variablecat(x y z) semantics:[variablecat()]
− examples/artificial/macros
@@ -1,126 +0,0 @@-% trivial example of the kid to parent rule-k2p-trivial() initial -Mother [cat:a]![] { Anchor anchor [ cat:x ]![] }--% note: the alphabetical names below are meaningless - they are just-% chinese numbers (which is why i follow them by the equivalent -% arabic numerals)-%-% why do i name them this way? dunno... figured they'd be easier-% to see or something---yi1() initial-YiMo [cat:a tb:?T]![tb:?B] {- YiLe anchor [ cat:x ]![]- YiRi type:subst [ cat:b ]![]-}--er2() initial-Mother [cat:b]![] {- Left anchor [ cat:x ]![]- Right type:subst [ cat:t1 ]![]-}--term(?C ?X) initial-T anchor [cat:?C foo:?X]![]--aux-bad() auxiliary-Mother [cat:t1 tb:foo]![] {- Left anchor [ cat:x ]![]- Foot type:foot [cat:t1]![tb:bar]-}--aux-good() auxiliary-MothA [cat:t1 tb:ping]![] {- LeftA anchor [cat:x]![]- FootA type:foot [cat:t1]![tb:ping]-}--aux-nepas () auxiliary-Mother [cat:t1 tb:ping]![] {- Left anchor [cat:x]![]- Foot type:foot [cat:t1]![tb:ping]- Right type:lex "pas"-}----% meant to receive substitution from san3 -% if it works - ?A should be set to bar-wu5 () initial-WuM [cat:a foo:?A]![] {- WuL anchor [cat:x]![]- WuR type:subst [cat:t1 foo:?A]![]-}--% a simple tb unification which ought to work-liu6-good () initial -Mother [cat:a]![cat:a] { Anchor anchor [cat:x]![] }--% unification + subst should work, but this should NOT propagate up! -% this should NOT propagate up-wu5-bad () initial-Mother [cat:a foo:?A]![] {- Anch anchor [cat:x]![]- Left type:subst [cat:t1 foo:?A]![]- Right type:subst [cat:t2 foo:?A]![]-}----% top-bot unification failure (simple)-liu6-bad1 () initial -Mother [cat:a]![cat:b] { Anch anchor [cat:x]![] }--% top-bot unification (complex)-liu6-bad2 () initial -Mother [cat:a tb:?X]![tb:?Y] {- Anch anchor [cat:x]![]- Left type:subst [cat:t1 foo:?X]![]- Right type:subst [cat:t2 foo:?Y]![]-}--% this should still be passed-iaf-killer-good (?X) initial-Mother [cat:a]![cat:a] {- Anch anchor [cat:x]![]- Left type:subst [cat:t1 idx:?X]![]- Right type:subst [cat:t2 idx:?X]![]-}--aconstr-with-anchor () initial-Anch anchor aconstr:noadj [cat:a]![]--% this succeeds iff thing is good or left unset-tb-unification-noadj () initial-M [cat:a]![] {- X type:subst [cat:x thing:?X]![thing:good]- Y anchor [cat:b]![]-}--tb-unification-bot() initial-M anchor [cat:a]![]--tb-unification-adj() auxiliary-M [cat:a]![idx:b] {- X anchor [cat:b]![]- Y type:foot [cat:a]![]-}--no-thing () initial-X anchor [cat:x]![]--thing-good () initial-X anchor [cat:x thing:good]![]--thing-bad () initial-X anchor [cat:x thing:bad]![]--lemanchor () initial-M [cat:x]![] {- X anchor [cat:x]![]- Y type:subst [cat:y]![lemanchor:hello]- Z type:subst [cat:y]![lemanchor:world]-}-
examples/artificial/suite view
@@ -25,5 +25,10 @@ tb-noadj-good-2 semantics:[tb-unification-noadj() thing-good()] tb-unification-1 semantics:[tb-unification-bot()] tb-unification-2 semantics:[tb-unification-bot() tb-unification-adj()]+tb-unification-na-good semantics:[tb-unification-na(good)]+tb-unification-anchor-good semantics:[tb-unification-anchor(good)] lemanchor semantics:[lemanchor()]+preterminal semantics:[preterminal()]+disjunction semantics:[disjunction()]+variablecat semantics:[variablecat()]
examples/artificial/suite-bad view
@@ -9,3 +9,5 @@ % aconstr:noadj nodes tb-noadj-bad semantics:[tb-unification-noadj() thing-bad()] +tb-unification-na-bad semantics:[tb-unification-na(bad)]+tb-unification-anchor-bad semantics:[tb-unification-anchor(bad)]
+ examples/artificial/trees view
@@ -0,0 +1,150 @@+% trivial example of the kid to parent rule+k2p-trivial() initial +Mother [cat:a]![] { Anchor anchor [ cat:x ]![] }++% note: the alphabetical names below are meaningless - they are just+% chinese numbers (which is why i follow them by the equivalent +% arabic numerals)+%+% why do i name them this way? dunno... figured they'd be easier+% to see or something+++yi1() initial+YiMo [cat:a tb:?T]![tb:?B] {+ YiLe anchor [ cat:x ]![]+ YiRi type:subst [ cat:b ]![]+}++er2() initial+Mother [cat:b]![] {+ Left anchor [ cat:x ]![]+ Right type:subst [ cat:t1 ]![]+}++term(?C ?X) initial+T anchor [cat:?C foo:?X]![]++aux-bad() auxiliary+Mother [cat:t1 tb:foo]![] {+ Left anchor [ cat:x ]![]+ Foot type:foot [cat:t1]![tb:bar]+}++aux-good() auxiliary+MothA [cat:t1 tb:ping]![] {+ LeftA anchor [cat:x]![]+ FootA type:foot [cat:t1]![tb:ping]+}++aux-nepas () auxiliary+Mother [cat:t1 tb:ping]![] {+ Left anchor [cat:x]![]+ Foot type:foot [cat:t1]![tb:ping]+ Right type:lex "pas"+}++++% meant to receive substitution from san3 +% if it works - ?A should be set to bar+wu5 () initial+WuM [cat:a foo:?A]![] {+ WuL anchor [cat:x]![]+ WuR type:subst [cat:t1 foo:?A]![]+}++% a simple tb unification which ought to work+liu6-good () initial +Mother [cat:a]![cat:a] { Anchor anchor [cat:x]![] }++% unification + subst should work, but this should NOT propagate up! +% this should NOT propagate up+wu5-bad () initial+Mother [cat:a foo:?A]![] {+ Anch anchor [cat:x]![]+ Left type:subst [cat:t1 foo:?A]![]+ Right type:subst [cat:t2 foo:?A]![]+}++++% top-bot unification failure (simple)+liu6-bad1 () initial +Mother [cat:a]![cat:b] { Anch anchor [cat:x]![] }++% top-bot unification (complex)+liu6-bad2 () initial +Mother [cat:a tb:?X]![tb:?Y] {+ Anch anchor [cat:x]![]+ Left type:subst [cat:t1 foo:?X]![]+ Right type:subst [cat:t2 foo:?Y]![]+}++% this should still be passed+iaf-killer-good (?X) initial+Mother [cat:a]![cat:a] {+ Anch anchor [cat:x]![]+ Left type:subst [cat:t1 idx:?X]![]+ Right type:subst [cat:t2 idx:?X]![]+}++aconstr-with-anchor () initial+Anch anchor aconstr:noadj [cat:a]![]++% this succeeds iff thing is good or left unset+tb-unification-noadj () initial+M [cat:a]![] {+ X type:subst [cat:x thing:?X]![thing:good]+ Y anchor [cat:b]![]+}++tb-unification-bot() initial+M anchor [cat:a]![]++tb-unification-adj() auxiliary+M [cat:a]![idx:b] {+ X anchor [cat:b]![]+ Y type:foot [cat:a]![]+}++tb-unification-na(?T) initial+X aconstr:noadj [cat:X thing:good]![thing:?T] {+ Y anchor [cat:X]![]+}++tb-unification-anchor(?T) initial+X [cat:X thing:good]![thing:?T] {+ Y anchor [cat:X thing:good]![thing:?T]+}+++no-thing () initial+X anchor [cat:x]![]++thing-good () initial+X anchor [cat:x thing:good]![]++thing-bad () initial+X anchor [cat:x thing:bad]![]++lemanchor () initial+M [cat:x]![] {+ X anchor [cat:x]![]+ Y type:subst [cat:y lemanchor:hello]![]+ Z type:subst [cat:y lemanchor:world]![]+}++preterminal () initial+M [cat:x]![] {+ X anchor [cat:x]![]+ Y [cat:y]![lemanchor:hello]+}+++disjunction(?X ?Y ?Z) initial+X anchor [cat:?X;?Y;?Z x:?X y:?Y z:?Z foo:?X/x|y|z;?Z;a]![]++variablecat(?X ?Y ?Z) initial+X anchor [cat:_ x:?X y:?Y z:?Z foo:?X/x|y|z;?Z;a]![]+
− examples/chatnoir/macros
@@ -1,132 +0,0 @@-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-% DETERMINERS-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%--Det(?I) auxiliary-n1[cat:n idx:?I det:plus qu:minus]![cat:n idx:?I det:plus qu:minus]-{- n2 anchor [cat:det]![]- n4 type:foot [cat:n idx:?I det:?_ qu:?_]![cat:n idx:?I det:minus qu:?_]-}--%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-% NOUNS-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%--% Common Nouns: voyage-nC(?I) initial-n1 anchor [cat:n idx:?I det:?_ qu:?_]![cat:n idx:?I det:minus qu:minus ]--% Proper Nouns: Jean-nP(?I) initial-n1 anchor [cat:n idx:?I det:plus qu:minus]![cat:n idx:?I det:plus qu:minus ]--%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-% ADJECTIVES-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%--adj_post(?I) auxiliary-n0[cat:n idx:?I det:?_ qu:?_]![cat:n idx:?I det:minus qu:minus ]-{- n1 type:foot [cat:n idx:?I det:minus qu:minus]!- [cat:n idx:?I det:minus qu:?_ ]- n2 anchor [cat:a]![]-}--adj_pre(?I) auxiliary-n0[cat:n idx:?I det:?_ qu:?_]![cat:n idx:?I det:minus qu:minus ]-{- n1 anchor [cat:a]![]- n3 type:foot [cat:n idx:?I det:minus qu:minus]!- [cat:n idx:?I det:minus qu:?_ ]-}--%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-% TRANSITIVE VERBS-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%--%infinitive- % chasser une souris vinfn1-vArity2:vinfn1(?E ?X ?Y) initial-n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p idx:?E mode:?_ sujidx:?_]-{- n2 anchor [cat:v idx:?E]![]- n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:?_ qu:?_ ]-}--% declarative- % le chat chasse la souris-vArity2:n0vn1(?E ?X ?Y) initial-n1[cat:p]![]-{- n2 type:subst [cat:n idx:?X det:plus qu:minus]!- [cat:n idx:?X det:?_ qu:?_ ]- n3 anchor [cat:v idx:?E]![]- n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y- det:?_ qu:?_ ]-}--% question sujet - % qui chasse une souris ?-vArity2:qu0vn1(?E ?X ?Y) initial-n1[cat:p]![]-{- n2 type:subst [cat:c idx:?X det:plus qu:minus]!- [cat:c idx:?X det:?_ qu:?_ ]- n3 anchor [cat:v idx:?E]![]- n5 type:subst [cat:n idx:?Y det:plus qu:minus]!- [cat:n idx:?Y det:?_ qu:?_ ]-}--% question objet- % que chasse le chat ?-vArity2:qu1vn0(?E ?X ?Y) initial-n1[cat:p]![]-{- n2 type:subst [cat:n idx:?Y det:plus qu:plus]!- [cat:n idx:?Y det:?_ qu:plus ]- n3[cat:p idx:?E]![]- {- % FIXME: EYK - the bottom node was cat:p, i set it to cat:v- % to validate- n4 anchor [cat:v idx:?E]![cat:v idx:?E]- n6 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X- det:?_ qu:?_ ]- }-}--% relative sujet-% le chat qui chasse la souris--vArity2:rel0vn1(?E ?X ?Y) auxiliary-n0[cat:n idx:?X det:plus qu:?_]![cat:n idx:?X det:?_ qu:?_ ]-{- n1 type:foot [cat:n idx:?X det:?_ qu:?_]![cat:n idx:?X det:?_ qu:?_ ]- n2[cat:p]![]- {- n3 type:subst [cat:c idx:?X det:plus qu:minus]!- [cat:c idx:?X det:?_ qu:?_ ]- n4 anchor [cat:v idx:?E]![]- n6 type:subst [cat:n idx:?Y det:plus qu:minus]!- [cat:n idx:?Y det:?_ qu:?_ ]- }}--% relative objet-% la souris que chasse le chat--vArity2:rel1vn0(?E ?X ?Y) auxiliary-n0[cat:n idx:?Y det:plus qu:?_]![cat:n idx:?Y det:?_ qu:?_ ]-{- n1 type:foot [cat:n idx:?Y det:?_ qu:?_]!- [cat:n idx:?Y det:?_ qu:?_ ]- n2[cat:p]![]- {- n3 type:subst [cat:c idx:?X det:plus qu:minus]!- [cat:c idx:?X det:?_ qu:?_ ]- n4 anchor [cat:v idx:?E]![]- n6 type:subst [cat:n idx:?X det:plus qu:minus]!- [cat:n idx:?X det:?_ qu:?_ ] - }-}--% vi: set cinoptions=0,p0:
+ examples/chatnoir/trees view
@@ -0,0 +1,132 @@+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+% DETERMINERS+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++Det(?I) auxiliary+n1[cat:n idx:?I det:plus qu:minus]![cat:n idx:?I det:plus qu:minus]+{+ n2 anchor [cat:det]![]+ n4 type:foot [cat:n idx:?I det:?_ qu:?_]![cat:n idx:?I det:minus qu:?_]+}++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+% NOUNS+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++% Common Nouns: voyage+nC(?I) initial+n1 anchor [cat:n idx:?I det:?_ qu:?_]![cat:n idx:?I det:minus qu:minus ]++% Proper Nouns: Jean+nP(?I) initial+n1 anchor [cat:n idx:?I det:plus qu:minus]![cat:n idx:?I det:plus qu:minus ]++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+% ADJECTIVES+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++adj_post(?I) auxiliary+n0[cat:n idx:?I det:?_ qu:?_]![cat:n idx:?I det:minus qu:minus ]+{+ n1 type:foot [cat:n idx:?I det:minus qu:minus]!+ [cat:n idx:?I det:minus qu:?_ ]+ n2 anchor [cat:a]![]+}++adj_pre(?I) auxiliary+n0[cat:n idx:?I det:?_ qu:?_]![cat:n idx:?I det:minus qu:minus ]+{+ n1 anchor [cat:a]![]+ n3 type:foot [cat:n idx:?I det:minus qu:minus]!+ [cat:n idx:?I det:minus qu:?_ ]+}++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%+% TRANSITIVE VERBS+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%++%infinitive+ % chasser une souris vinfn1+vArity2:vinfn1(?E ?X ?Y) initial+n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p idx:?E mode:?_ sujidx:?_]+{+ n2 anchor [cat:v idx:?E]![]+ n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:?_ qu:?_ ]+}++% declarative+ % le chat chasse la souris+vArity2:n0vn1(?E ?X ?Y) initial+n1[cat:p]![]+{+ n2 type:subst [cat:n idx:?X det:plus qu:minus]!+ [cat:n idx:?X det:?_ qu:?_ ]+ n3 anchor [cat:v idx:?E]![]+ n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y+ det:?_ qu:?_ ]+}++% question sujet + % qui chasse une souris ?+vArity2:qu0vn1(?E ?X ?Y) initial+n1[cat:p]![]+{+ n2 type:subst [cat:c idx:?X det:plus qu:minus]!+ [cat:c idx:?X det:?_ qu:?_ ]+ n3 anchor [cat:v idx:?E]![]+ n5 type:subst [cat:n idx:?Y det:plus qu:minus]!+ [cat:n idx:?Y det:?_ qu:?_ ]+}++% question objet+ % que chasse le chat ?+vArity2:qu1vn0(?E ?X ?Y) initial+n1[cat:p]![]+{+ n2 type:subst [cat:n idx:?Y det:plus qu:plus]!+ [cat:n idx:?Y det:?_ qu:plus ]+ n3[cat:p idx:?E]![]+ {+ % FIXME: EYK - the bottom node was cat:p, i set it to cat:v+ % to validate+ n4 anchor [cat:v idx:?E]![cat:v idx:?E]+ n6 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X+ det:?_ qu:?_ ]+ }+}++% relative sujet+% le chat qui chasse la souris++vArity2:rel0vn1(?E ?X ?Y) auxiliary+n0[cat:n idx:?X det:plus qu:?_]![cat:n idx:?X det:?_ qu:?_ ]+{+ n1 type:foot [cat:n idx:?X det:?_ qu:?_]![cat:n idx:?X det:?_ qu:?_ ]+ n2[cat:p]![]+ {+ n3 type:subst [cat:c idx:?X det:plus qu:minus]!+ [cat:c idx:?X det:?_ qu:?_ ]+ n4 anchor [cat:v idx:?E]![]+ n6 type:subst [cat:n idx:?Y det:plus qu:minus]!+ [cat:n idx:?Y det:?_ qu:?_ ]+ }}++% relative objet+% la souris que chasse le chat++vArity2:rel1vn0(?E ?X ?Y) auxiliary+n0[cat:n idx:?Y det:plus qu:?_]![cat:n idx:?Y det:?_ qu:?_ ]+{+ n1 type:foot [cat:n idx:?Y det:?_ qu:?_]!+ [cat:n idx:?Y det:?_ qu:?_ ]+ n2[cat:p]![]+ {+ n3 type:subst [cat:c idx:?X det:plus qu:minus]!+ [cat:c idx:?X det:?_ qu:?_ ]+ n4 anchor [cat:v idx:?E]![]+ n6 type:subst [cat:n idx:?X det:plus qu:minus]!+ [cat:n idx:?X det:?_ qu:?_ ] + }+}++% vi: set cinoptions=0,p0:
− examples/demo/macros
@@ -1,439 +0,0 @@-%% 02 april 2004-%% 1. Jean promet un cadeau a Marie-%% 2. Jean promet a Marie de partir-%% 3. Qui promet un cadeau a Marie?-%% 4. Que promet Jean a Marie?-%% 5. A qui Jean promet-il un cadeau?-%% 6. la personne qui promet un cadeau a Marie-%% 7. le cadeau que Jean promet a Marie-%% 8. la personne a qui Jean promet un cadeau-%% 9. promettre un cadeau a Marie-%% 10. promettant un cadeau a Marie-%% 11. donner un livre a marie--Det(?I) auxiliary-n1[cat:n idx:?I det:_ qu:minus]![cat:n idx:?I det:_ qu:minus]-{- n2 anchor [cat:det]![]- n4 type:foot [cat:n idx:?I det:_ qu:_ ]![cat:n idx:?I det:minus qu:_ ]-}-- % Common Nouns: voyage-nC(?I) initial- n1 anchor [cat:n idx:?I det:_ qu:?W ]![cat:n idx:?I det:minus qu:minus ]-% Proper Nouns: Jean--nP(?I) initial- n1 anchor [cat:n idx:?I det:plus qu:minus]![cat:n idx:?I det:plus qu:minus ]-- %1 declarative gn promet gn sp_a-n0vn1sp2(?E ?X ?Y ?Z) initial- n1[cat:p]![]-{- n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]- n3 anchor [cat:v idx:?E]![]- n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]- n6[cat:sp idx:?Z det:plus]![det:_ ]- { n8[cat:prep]![]- {- n9 type:lex "a"- }- n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z- det:_ qu:_] - }-}-- %2 infinitive V GN SP_a-vinfn1sp2(?E ?X ?Y ?Z) initial- n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p idx:?E mode:_ sujidx:_]-{- n2 anchor [cat:v idx:?E]![]- n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]- n5[cat:sp idx:?Z det:plus]![det:_ ]- { n6[cat:prep]![]- {- n7 type:lex "a"- }- n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z- det:_ qu:_] - }-}-- %3 question sujet qui V GN GP_a ?-qu0vn1sp2(?E ?X ?Y ?Z) initial- n1[cat:p]![]-{- n2 type:subst [cat:c idx:?X det:plus qu:minus]![idx:?X det:_ qu:_ ]- n3 anchor [cat:v idx:?E]![]- n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]- n6[cat:sp idx:?Z det:plus]![det:_ ]- { n8[cat:prep]![]- {- n9 type:lex "a"- }- n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z det:_ qu:_ ] - }-}-- %4 question objet-qu1vn0sp2(?E ?X ?Y ?Z) initial- n1[cat:p]![]-{- n2 type:subst [cat:n idx:?Y det:plus qu:plus]![cat:n idx:?Y det:_ qu:plus ]- n3[cat:p idx:?E]![]- {- n4 anchor [cat:v idx:?E]![idx:?E]- n6 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X- det:_ qu:_ ]- n7[cat:sp idx:?Z det:plus]![det:_ ]- { n8[cat:prep]![]- {- n9 type:lex "a"- }- n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z det:_ qu:_] - }- }-}-- %5 question objet indirect-qu2n0vn1(?E ?X ?Y ?Z) initial- n1[cat:p]![]-{- n2[cat:sp idx:?Z det:plus]![det:_ ]- { n3[cat:prep]![]- {- n4 type:lex "a"- }- n5 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z det:_ qu:plus] - }- n6[cat:p idx:?E]![]- {- n7 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]- n8 anchor [cat:v idx:?E]![idx:?E]- n10 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]- }-}--%6 relative sujet qui V gn sp_a -rel0vn1sp2(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?X det:plus qu:_]![cat:n idx:?X det:_ qu:_ ]-{- n1 type:foot [cat:n idx:?X det:_ qu:_]![cat:n idx:?X det:_ qu:_ ]- n2[cat:p]![]- {- n3 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]- n4 anchor [cat:v idx:?E]![]- n6 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]- n7[cat:sp idx:?Z ]![]- { n8[cat:prep]![]- {- n9 type:lex "a"- }- n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:_- det:_ qu:_] - }- n9[cat:p]![]- {n10[cat:prep]![]- {- n11 type:lex "de"- } - n12 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z - mode:_ sujidx:_]- }}}--%7 relative objet-rel1vn0sp2(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?Y det:plus qu:_]![cat:n idx:?Y det:_ qu:_ ]-{- n1 type:foot [cat:n idx:?Y det:_ qu:_]![cat:n idx:?Y det:_ qu:_ ]- n2[cat:p]![]- {- n3 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]- n4 anchor [cat:v idx:?E]![]- n6 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]- n7[cat:sp idx:?Z ]![]- { n8[cat:prep]![]- {- n9 type:lex "a"- }- n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:_- det:_ qu:_] - }- }-}--%8 relative objet indirect-rel2n0vn1(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?Z det:plus qu:_]![cat:n idx:?Z det:_ qu:_ ]-{- n1 type:foot [cat:n idx:?Z det:_ qu:_]![cat:n idx:?Z det:_ qu:_]- n2[cat:p]![]- {- n3[cat:sp idx:?Z det:plus]![det:_ ]- { n4[cat:prep]![]- {- n5 type:lex "a"- }- n6 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z det:_ qu:plus] - }- n7[cat:p idx:?E]![]- {- n8 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]- n9 anchor [cat:v idx:?E]![cat:p idx:?E]- n11 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]- }- }-}-- %9 declarative GN V GN_a Pinf_de-n0vsp2pinf1(?E ?X ?Y ?Z) initial- n1[cat:p]![]-{- n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]- n3 anchor [cat:v idx:?E]![]- n5[cat:sp idx:?Y det:plus]![det:_ ]- { n6[cat:prep]![]- {- n7 type:lex "a"- }- n8 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_] - }- n9[cat:p]![]- {n10[cat:prep]![]- {- n11 type:lex "de"- } - n12 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![idx:?Z mode:_ sujidx:_]- }-}-- %10 infinitive V SP_a Inf_de-vinfsp2pinf1(?E ?X ?Y ?Z) initial- n1[cat:p idx:?E mode:inf sujidx:?X]![idx:?Y mode:_ sujidx:_]-{- n2 anchor [cat:v idx:?E]![]- n4[cat:sp idx:?Z det:plus]![det:_ ]- { n5[cat:prep]![]- {- n6 type:lex "a"- }- n7 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z- det:_ qu:_] - }- n8[cat:p]![]- {n9[cat:prep]![]- {- n10 type:lex "de"- } - n11 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z - mode:_ sujidx:_]- }-}-- %11 question sujet qui V GP_a Pinf_de ?-qu0vsp2pinf1(?E ?X ?Y ?Z) initial - n1[cat:p]![]-{- n2 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]- n3 anchor [cat:v idx:?E]![]- n5[cat:sp idx:?Z det:plus]![det:_ ]- { n6[cat:prep]![]- {- n7 type:lex "a"- }- n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z det:_ qu:_ ] - }- n9[cat:p]![]- {n10[cat:prep]![]- {- n11 type:lex "de"- } - n12 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z - mode:_ sujidx:_]- }}-- %12 question objet indirect-qu2n0vpinf1(?E ?X ?Y ?Z) initial- n1[cat:p]![]-{- n2[cat:sp idx:?Z det:plus]![det:_ ]- { n3[cat:prep]![]- {- n4 type:lex "a"- }- n5 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z det:_ qu:plus] - }- n6[cat:p idx:?E]![]- {- n7 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]- n8 anchor [cat:v idx:?E]![cat:p idx:?E]- }- n10[cat:prep]![]- {- n11 type:lex "de"- } - n12 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z - mode:_ sujidx:_]-}--%13 relative sujet qui V sp_a pinf_de-rel0vsp2pinf1(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?X det:plus qu:_]![cat:n idx:?X det:_ qu:_ ]-{- n1 type:foot [cat:n idx:?X det:_ qu:_]![cat:n idx:?X det:_ qu:_ ]- n2[cat:p]![]- {- n3 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]- n4 anchor [cat:v idx:?E]![]- n6[cat:sp idx:?Z ]![]- { n7[cat:prep]![]- {- n8 type:lex "a"- }- n9 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:_- det:_ qu:_] - }- n10[cat:p]![]- {n11[cat:prep]![]- {- n12 type:lex "de"- } - n13 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z - mode:_ sujidx:_]- }}}--%14 relative objet indirect a qui GN v Pinf_de-rel2n0vpinf1(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?Z det:plus qu:_]![cat:n idx:?Z det:_ qu:_ ]-{- n1 type:foot [cat:n idx:?Z det:_ qu:_]![cat:n idx:?Z det:_ qu:_]- n2[cat:p]![]- {- n3[cat:sp idx:?Z det:plus]![det:_ ]- { n4[cat:prep]![]- {- n5 type:lex "a"- }- n6 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z det:_ qu:plus] - }- n7[cat:p idx:?E]![]- {- n8 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]- n9 anchor [cat:v idx:?E]![cat:p idx:?E]- }- n9[cat:p]![]- {n10[cat:prep]![]- {- n11 type:lex "de"- } - n12 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y- mode:_ sujidx:_]- }- }}--- %15 declarative gn0 persuade gn2 pinf_de1 n0vn2pinf1 -n0vn2pinf1(?E ?X ?Y ?Z) initial- n1[cat:p]![]-{- n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]- n3 anchor [cat:v idx:?E]![]- n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_]- n6[cat:p]![]- {n7[cat:prep]![]- {- n8 type:lex "de"- } - n9 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![idx:?Z mode:_ sujidx:_]- }-}-- %15 infinitive persuader gn pinf_de vinfn2pinf1-vinfn2pinf1(?E ?X ?Y ?Z) initial- n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p idx:?Y mode:_ sujidx:_]-{- n2 anchor [cat:v idx:?E]![]- n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y- det:_ qu:_] - n5[cat:p]![]- {n6[cat:prep]![]- {- n7 type:lex "de"- } - n8 type:subst [cat:p idx:?Z mode:inf sujidx:?Y]![cat:p idx:?Z - mode:_ sujidx:_]- }-}-- %16 qu-sujet qui persuade gn pinf_de ? qu0vn2pinf1-qu0vn2pinf1(?E ?X ?Y ?Z) initial- n1[cat:p]![]-{- n2 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]- n3 anchor [cat:v idx:?E]![]- n5 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z det:_ qu:_ ] - n6[cat:p]![]- {n7[cat:prep]![]- {- n8 type:lex "de"- } - n9 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z - mode:_ sujidx:_]- }}-- %17 qu-obj qui gn persuade-il pinf_de ? qu2n0vpinf1-qu2n0vpinf1(?E ?X ?Y ?Z) initial- n1[cat:p]![]-{- n2 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z det:_ qu:plus] - n3[cat:p idx:?E]![]- {- n4 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]- n5 anchor [cat:v idx:?E]![cat:p idx:?E]- }- n7[cat:prep]![]- {- n8 type:lex "de"- } - n9 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y - mode:_ sujidx:_]-}--%18 rel-sjt n qui persuade gn pinf_de rel0vn2pinf1-rel0vn2pinf1(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?X det:plus qu:_]![cat:n idx:?X det:_ qu:_ ]-{- n1 type:foot [cat:n idx:?X det:_ qu:_]![cat:n idx:?X det:_ qu:_ ]- n2[cat:p]![]- {- n3 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]- n4 anchor [cat:v idx:?E]![]- n6 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:_- det:_ qu:_] - n7[cat:p]![]- {n8[cat:prep]![]- {- n9 type:lex "de"- } - n10 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y - mode:_ sujidx:_]- }}}--%19 rel-obj n dont gn persuade gn rel1n0vn2-rel1n0vn2(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?Y det:plus qu:_]![cat:n idx:?Y det:_ qu:_ ]-{- n1 type:foot [cat:n idx:?Y det:_ qu:_]![cat:n idx:?Y det:_ qu:_]- n2[cat:p]![]- {- n3 type:subst [cat:c idx:?Y det:plus qu:_]![cat:c idx:?Y det:_ qu:_] - n4[cat:p idx:?E]![]- {- n5 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]- n6 anchor [cat:v idx:?E]![cat:p idx:?E]- }- n8 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y - det:_ qu:minus ]- }-}-
+ examples/demo/trees view
@@ -0,0 +1,439 @@+%% 02 april 2004+%% 1. Jean promet un cadeau a Marie+%% 2. Jean promet a Marie de partir+%% 3. Qui promet un cadeau a Marie?+%% 4. Que promet Jean a Marie?+%% 5. A qui Jean promet-il un cadeau?+%% 6. la personne qui promet un cadeau a Marie+%% 7. le cadeau que Jean promet a Marie+%% 8. la personne a qui Jean promet un cadeau+%% 9. promettre un cadeau a Marie+%% 10. promettant un cadeau a Marie+%% 11. donner un livre a marie++Det(?I) auxiliary+n1[cat:n idx:?I det:_ qu:minus]![cat:n idx:?I det:_ qu:minus]+{+ n2 anchor [cat:det]![]+ n4 type:foot [cat:n idx:?I det:_ qu:_ ]![cat:n idx:?I det:minus qu:_ ]+}++ % Common Nouns: voyage+nC(?I) initial+ n1 anchor [cat:n idx:?I det:_ qu:?W ]![cat:n idx:?I det:minus qu:minus ]+% Proper Nouns: Jean++nP(?I) initial+ n1 anchor [cat:n idx:?I det:plus qu:minus]![cat:n idx:?I det:plus qu:minus ]++ %1 declarative gn promet gn sp_a+n0vn1sp2(?E ?X ?Y ?Z) initial+ n1[cat:p]![]+{+ n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]+ n3 anchor [cat:v idx:?E]![]+ n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]+ n6[cat:sp idx:?Z det:plus]![det:_ ]+ { n8[cat:prep]![]+ {+ n9 type:lex "a"+ }+ n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z+ det:_ qu:_] + }+}++ %2 infinitive V GN SP_a+vinfn1sp2(?E ?X ?Y ?Z) initial+ n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p idx:?E mode:_ sujidx:_]+{+ n2 anchor [cat:v idx:?E]![]+ n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]+ n5[cat:sp idx:?Z det:plus]![det:_ ]+ { n6[cat:prep]![]+ {+ n7 type:lex "a"+ }+ n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z+ det:_ qu:_] + }+}++ %3 question sujet qui V GN GP_a ?+qu0vn1sp2(?E ?X ?Y ?Z) initial+ n1[cat:p]![]+{+ n2 type:subst [cat:c idx:?X det:plus qu:minus]![idx:?X det:_ qu:_ ]+ n3 anchor [cat:v idx:?E]![]+ n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]+ n6[cat:sp idx:?Z det:plus]![det:_ ]+ { n8[cat:prep]![]+ {+ n9 type:lex "a"+ }+ n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z det:_ qu:_ ] + }+}++ %4 question objet+qu1vn0sp2(?E ?X ?Y ?Z) initial+ n1[cat:p]![]+{+ n2 type:subst [cat:n idx:?Y det:plus qu:plus]![cat:n idx:?Y det:_ qu:plus ]+ n3[cat:p idx:?E]![]+ {+ n4 anchor [cat:v idx:?E]![idx:?E]+ n6 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X+ det:_ qu:_ ]+ n7[cat:sp idx:?Z det:plus]![det:_ ]+ { n8[cat:prep]![]+ {+ n9 type:lex "a"+ }+ n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z det:_ qu:_] + }+ }+}++ %5 question objet indirect+qu2n0vn1(?E ?X ?Y ?Z) initial+ n1[cat:p]![]+{+ n2[cat:sp idx:?Z det:plus]![det:_ ]+ { n3[cat:prep]![]+ {+ n4 type:lex "a"+ }+ n5 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z det:_ qu:plus] + }+ n6[cat:p idx:?E]![]+ {+ n7 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]+ n8 anchor [cat:v idx:?E]![idx:?E]+ n10 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]+ }+}++%6 relative sujet qui V gn sp_a +rel0vn1sp2(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?X det:plus qu:_]![cat:n idx:?X det:_ qu:_ ]+{+ n1 type:foot [cat:n idx:?X det:_ qu:_]![cat:n idx:?X det:_ qu:_ ]+ n2[cat:p]![]+ {+ n3 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]+ n4 anchor [cat:v idx:?E]![]+ n6 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]+ n7[cat:sp idx:?Z ]![]+ { n8[cat:prep]![]+ {+ n9 type:lex "a"+ }+ n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:_+ det:_ qu:_] + }+ n9[cat:p]![]+ {n10[cat:prep]![]+ {+ n11 type:lex "de"+ } + n12 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z + mode:_ sujidx:_]+ }}}++%7 relative objet+rel1vn0sp2(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?Y det:plus qu:_]![cat:n idx:?Y det:_ qu:_ ]+{+ n1 type:foot [cat:n idx:?Y det:_ qu:_]![cat:n idx:?Y det:_ qu:_ ]+ n2[cat:p]![]+ {+ n3 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]+ n4 anchor [cat:v idx:?E]![]+ n6 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]+ n7[cat:sp idx:?Z ]![]+ { n8[cat:prep]![]+ {+ n9 type:lex "a"+ }+ n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:_+ det:_ qu:_] + }+ }+}++%8 relative objet indirect+rel2n0vn1(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?Z det:plus qu:_]![cat:n idx:?Z det:_ qu:_ ]+{+ n1 type:foot [cat:n idx:?Z det:_ qu:_]![cat:n idx:?Z det:_ qu:_]+ n2[cat:p]![]+ {+ n3[cat:sp idx:?Z det:plus]![det:_ ]+ { n4[cat:prep]![]+ {+ n5 type:lex "a"+ }+ n6 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z det:_ qu:plus] + }+ n7[cat:p idx:?E]![]+ {+ n8 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]+ n9 anchor [cat:v idx:?E]![cat:p idx:?E]+ n11 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_ ]+ }+ }+}++ %9 declarative GN V GN_a Pinf_de+n0vsp2pinf1(?E ?X ?Y ?Z) initial+ n1[cat:p]![]+{+ n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]+ n3 anchor [cat:v idx:?E]![]+ n5[cat:sp idx:?Y det:plus]![det:_ ]+ { n6[cat:prep]![]+ {+ n7 type:lex "a"+ }+ n8 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_] + }+ n9[cat:p]![]+ {n10[cat:prep]![]+ {+ n11 type:lex "de"+ } + n12 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![idx:?Z mode:_ sujidx:_]+ }+}++ %10 infinitive V SP_a Inf_de+vinfsp2pinf1(?E ?X ?Y ?Z) initial+ n1[cat:p idx:?E mode:inf sujidx:?X]![idx:?Y mode:_ sujidx:_]+{+ n2 anchor [cat:v idx:?E]![]+ n4[cat:sp idx:?Z det:plus]![det:_ ]+ { n5[cat:prep]![]+ {+ n6 type:lex "a"+ }+ n7 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z+ det:_ qu:_] + }+ n8[cat:p]![]+ {n9[cat:prep]![]+ {+ n10 type:lex "de"+ } + n11 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z + mode:_ sujidx:_]+ }+}++ %11 question sujet qui V GP_a Pinf_de ?+qu0vsp2pinf1(?E ?X ?Y ?Z) initial + n1[cat:p]![]+{+ n2 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]+ n3 anchor [cat:v idx:?E]![]+ n5[cat:sp idx:?Z det:plus]![det:_ ]+ { n6[cat:prep]![]+ {+ n7 type:lex "a"+ }+ n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z det:_ qu:_ ] + }+ n9[cat:p]![]+ {n10[cat:prep]![]+ {+ n11 type:lex "de"+ } + n12 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z + mode:_ sujidx:_]+ }}++ %12 question objet indirect+qu2n0vpinf1(?E ?X ?Y ?Z) initial+ n1[cat:p]![]+{+ n2[cat:sp idx:?Z det:plus]![det:_ ]+ { n3[cat:prep]![]+ {+ n4 type:lex "a"+ }+ n5 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z det:_ qu:plus] + }+ n6[cat:p idx:?E]![]+ {+ n7 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]+ n8 anchor [cat:v idx:?E]![cat:p idx:?E]+ }+ n10[cat:prep]![]+ {+ n11 type:lex "de"+ } + n12 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z + mode:_ sujidx:_]+}++%13 relative sujet qui V sp_a pinf_de+rel0vsp2pinf1(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?X det:plus qu:_]![cat:n idx:?X det:_ qu:_ ]+{+ n1 type:foot [cat:n idx:?X det:_ qu:_]![cat:n idx:?X det:_ qu:_ ]+ n2[cat:p]![]+ {+ n3 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]+ n4 anchor [cat:v idx:?E]![]+ n6[cat:sp idx:?Z ]![]+ { n7[cat:prep]![]+ {+ n8 type:lex "a"+ }+ n9 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:_+ det:_ qu:_] + }+ n10[cat:p]![]+ {n11[cat:prep]![]+ {+ n12 type:lex "de"+ } + n13 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z + mode:_ sujidx:_]+ }}}++%14 relative objet indirect a qui GN v Pinf_de+rel2n0vpinf1(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?Z det:plus qu:_]![cat:n idx:?Z det:_ qu:_ ]+{+ n1 type:foot [cat:n idx:?Z det:_ qu:_]![cat:n idx:?Z det:_ qu:_]+ n2[cat:p]![]+ {+ n3[cat:sp idx:?Z det:plus]![det:_ ]+ { n4[cat:prep]![]+ {+ n5 type:lex "a"+ }+ n6 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z det:_ qu:plus] + }+ n7[cat:p idx:?E]![]+ {+ n8 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]+ n9 anchor [cat:v idx:?E]![cat:p idx:?E]+ }+ n9[cat:p]![]+ {n10[cat:prep]![]+ {+ n11 type:lex "de"+ } + n12 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y+ mode:_ sujidx:_]+ }+ }}+++ %15 declarative gn0 persuade gn2 pinf_de1 n0vn2pinf1 +n0vn2pinf1(?E ?X ?Y ?Z) initial+ n1[cat:p]![]+{+ n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]+ n3 anchor [cat:v idx:?E]![]+ n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y det:_ qu:_]+ n6[cat:p]![]+ {n7[cat:prep]![]+ {+ n8 type:lex "de"+ } + n9 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![idx:?Z mode:_ sujidx:_]+ }+}++ %15 infinitive persuader gn pinf_de vinfn2pinf1+vinfn2pinf1(?E ?X ?Y ?Z) initial+ n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p idx:?Y mode:_ sujidx:_]+{+ n2 anchor [cat:v idx:?E]![]+ n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y+ det:_ qu:_] + n5[cat:p]![]+ {n6[cat:prep]![]+ {+ n7 type:lex "de"+ } + n8 type:subst [cat:p idx:?Z mode:inf sujidx:?Y]![cat:p idx:?Z + mode:_ sujidx:_]+ }+}++ %16 qu-sujet qui persuade gn pinf_de ? qu0vn2pinf1+qu0vn2pinf1(?E ?X ?Y ?Z) initial+ n1[cat:p]![]+{+ n2 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]+ n3 anchor [cat:v idx:?E]![]+ n5 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z det:_ qu:_ ] + n6[cat:p]![]+ {n7[cat:prep]![]+ {+ n8 type:lex "de"+ } + n9 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z + mode:_ sujidx:_]+ }}++ %17 qu-obj qui gn persuade-il pinf_de ? qu2n0vpinf1+qu2n0vpinf1(?E ?X ?Y ?Z) initial+ n1[cat:p]![]+{+ n2 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z det:_ qu:plus] + n3[cat:p idx:?E]![]+ {+ n4 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]+ n5 anchor [cat:v idx:?E]![cat:p idx:?E]+ }+ n7[cat:prep]![]+ {+ n8 type:lex "de"+ } + n9 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y + mode:_ sujidx:_]+}++%18 rel-sjt n qui persuade gn pinf_de rel0vn2pinf1+rel0vn2pinf1(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?X det:plus qu:_]![cat:n idx:?X det:_ qu:_ ]+{+ n1 type:foot [cat:n idx:?X det:_ qu:_]![cat:n idx:?X det:_ qu:_ ]+ n2[cat:p]![]+ {+ n3 type:subst [cat:c idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:_ ]+ n4 anchor [cat:v idx:?E]![]+ n6 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:_+ det:_ qu:_] + n7[cat:p]![]+ {n8[cat:prep]![]+ {+ n9 type:lex "de"+ } + n10 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y + mode:_ sujidx:_]+ }}}++%19 rel-obj n dont gn persuade gn rel1n0vn2+rel1n0vn2(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?Y det:plus qu:_]![cat:n idx:?Y det:_ qu:_ ]+{+ n1 type:foot [cat:n idx:?Y det:_ qu:_]![cat:n idx:?Y det:_ qu:_]+ n2[cat:p]![]+ {+ n3 type:subst [cat:c idx:?Y det:plus qu:_]![cat:c idx:?Y det:_ qu:_] + n4[cat:p idx:?E]![]+ {+ n5 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X det:_ qu:minus ]+ n6 anchor [cat:v idx:?E]![cat:p idx:?E]+ }+ n8 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y + det:_ qu:minus ]+ }+}+
examples/ej/lexicon view
@@ -48,9 +48,13 @@ Vinny Pn(?Entity ! agr:sg3) semantics:[name(_ ?Entity vincent)] +% Unicode Émilie Pn(?Entity ! agr:sg3) semantics:[name(_ ?Entity émilie)] +% string literals+"Joe \"the Boxer\" Stephens" Pn(?Entity ! agr:sg3)+semantics:[name(_ ?Entity joe_stephens)] %% Verbs %% intransitive verbs
− examples/ej/macros
@@ -1,92 +0,0 @@-%% -%% Tree Templates-%%-%%-%% INITIAL TREES-%% s trees-%% (IntrV, TrV, TrVPP)-%% np trees-%% (Dp, Pn)-%% n trees-%% (Cn)-%%-%% AUXILIARY TREES-%% n trees-%% (Adj)-%% vp trees-%% (Adv)---%% INITIAL TREES--vArity1:IntrV(?Event ?Agent ! agr:?A) initial- n1[cat:s idx:?Event]![]- { - n2 type:subst [cat:np idx:?Agent]![]- n3 [cat:vp idx:?Event]![]- {- n4 anchor [cat:v idx:?Event]![]- }- }--vArity2:TrV(?Event ?Agent ?Experiencer ! agr:?A) initial- n1[cat:s idx:?Event]![]- {- n2 type:subst [cat:np idx:?Agent ]![]- n3[cat:vp idx:?Event]![]- {- n4 anchor [cat:v idx:?Event]![]- n6 type:subst [cat:np idx:?Experiencer ]![]- }- }--vArity3:TrVPP(?Event ?Agent ?Theme ?Loc ! agr:?A) initial- n1[cat:s idx:?Event]![]- {- n2 type:subst [cat:np idx:?Agent ]![]- n3[cat:vp idx:?Event]![]- {- n4 anchor [cat:v idx:?Event]![]- n6 type:subst [cat:np idx:?Theme ]![]- n7 aconstr:noadj [cat:pp]![]- {- n8[cat:p]![]- {- n9 type:lex "from"- }- n10 type:subst [cat:np idx:?Loc ]![]- }- }- }--Dp(?Entity ! agr:?A) initial- n1[cat:np idx:?Entity]![]- {- n2 anchor [cat:det]![]- n4 type:subst [cat:n idx:?Entity ]![]- }--Pn(?Entity ! agr:?A) initial- n1[cat:np idx:?Entity]![]- {- n2 anchor [cat:pn idx:?Entity]![]- }--Cn(?Entity ! agr:?A) initial- n1 anchor [cat:n idx:?Entity]![]--%% ?AUXILIARY ?TREES--Adj(?Entity) auxiliary- n1[cat:n idx:?Entity]![]- {- n2 anchor [cat:adj]![]- n4 type:foot [cat:n idx:?Entity ]![]- }--Adv(?Event) auxiliary- n1[cat:vp idx:?Event]![]- {- n2 type:foot [cat:vp idx:?Event]![]- n3 anchor [cat:adv]![]- }
examples/ej/suite view
@@ -18,6 +18,12 @@ name(s2 ex émilie)] [Vincent loves Émilie] +v_loves_j+semantics: [ name(s1 a vincent)+ love(e a ex)+ name(s2 ex joe_stephens)]+[Vincent loves Joe "the Boxer" Stephens]+ v_loves_m_f semantics : [name(s1 a vincent) love(e a ex)
+ examples/ej/trees view
@@ -0,0 +1,92 @@+%% +%% Tree Templates+%%+%%+%% INITIAL TREES+%% s trees+%% (IntrV, TrV, TrVPP)+%% np trees+%% (Dp, Pn)+%% n trees+%% (Cn)+%%+%% AUXILIARY TREES+%% n trees+%% (Adj)+%% vp trees+%% (Adv)+++%% INITIAL TREES++vArity1:IntrV(?Event ?Agent ! agr:?A) initial+ n1[cat:s idx:?Event]![]+ { + n2 type:subst [cat:np idx:?Agent]![]+ n3 [cat:vp idx:?Event]![]+ {+ n4 anchor [cat:v idx:?Event]![]+ }+ }++vArity2:TrV(?Event ?Agent ?Experiencer ! agr:?A) initial+ n1[cat:s idx:?Event]![]+ {+ n2 type:subst [cat:np idx:?Agent ]![]+ n3[cat:vp idx:?Event]![]+ {+ n4 anchor [cat:v idx:?Event]![]+ n6 type:subst [cat:np idx:?Experiencer ]![]+ }+ }++vArity3:TrVPP(?Event ?Agent ?Theme ?Loc ! agr:?A) initial+ n1[cat:s idx:?Event]![]+ {+ n2 type:subst [cat:np idx:?Agent ]![]+ n3[cat:vp idx:?Event]![]+ {+ n4 anchor [cat:v idx:?Event]![]+ n6 type:subst [cat:np idx:?Theme ]![]+ n7 aconstr:noadj [cat:pp]![]+ {+ n8[cat:p]![]+ {+ n9 type:lex "from"+ }+ n10 type:subst [cat:np idx:?Loc ]![]+ }+ }+ }++Dp(?Entity ! agr:?A) initial+ n1[cat:np idx:?Entity]![]+ {+ n2 anchor [cat:det]![]+ n4 type:subst [cat:n idx:?Entity ]![]+ }++Pn(?Entity ! agr:?A) initial+ n1[cat:np idx:?Entity]![]+ {+ n2 anchor [cat:pn idx:?Entity]![]+ }++Cn(?Entity ! agr:?A) initial+ n1 anchor [cat:n idx:?Entity]![]++%% ?AUXILIARY ?TREES++Adj(?Entity) auxiliary+ n1[cat:n idx:?Entity]![]+ {+ n2 anchor [cat:adj]![]+ n4 type:foot [cat:n idx:?Entity ]![]+ }++Adv(?Event) auxiliary+ n1[cat:vp idx:?Event]![]+ {+ n2 type:foot [cat:vp idx:?Event]![]+ n3 anchor [cat:adv]![]+ }
− examples/nosemantics/macros
@@ -1,363 +0,0 @@-%%-%% GENI Macro-%% This macro was automatically generated by-%% a tagml->macro script, tagml2genimacro.xsl-%% 2005-%% contact: kow@loria.fr lai@loria.fr--n() initial-n1 anchor--{-}--pro() initial-n1 anchor--{-}--pro_substantif() initial-n1 [cat:nom]![cat:nom]-{-n1.1 anchor-}--det_n() auxiliary-n1 [cat:nom]![cat:nom]-{-n1.1 anchor-n1.2 type:foot [cat:nom]![cat:nom]-}--n_la() auxiliary-n1 [cat:nom]![cat:nom]-{-n1.1 type:foot [cat:nom]![cat:nom]-n1.2 anchor-}--det_substantif() initial-n1 [cat:nom]![cat:nom]-{-n1.1 anchor-}--det_det() auxiliary-n1 [cat:det]![cat:det]-{-n1.1 type:foot [cat:det]![cat:det]-n1.2 anchor-}--np() initial-n1 anchor--{-}--np_substantif() initial-n1 [cat:nom]![cat:nom]-{-n1.1 anchor-}--n_np() auxiliary-n1 [cat:nom]![cat:nom]-{-n1.1 type:foot [cat:nom]![cat:nom]-n1.2 anchor-}--n_con_n() initial-n1 [cat:nom]![cat:nom]-{-n1.1 type:subst [cat:nom]![cat:nom]-n1.2 anchor-n1.3 type:subst [cat:nom]![cat:nom]-}--enum_n() auxiliary-n1 [cat:nom]![cat:nom]-{-n1.1 type:foot [cat:nom]![cat:nom]-n1.2 anchor-}--n_pred() initial-n1 [cat:nom]![cat:nom]-{-n1.1 type:subst [cat:nom]![cat:nom]-n1.2 [cat:gp]![cat:gp]-{-n1.2.1 anchor-n1.2.2 type:subst [cat:nom]![cat:nom]-}-}--compl_n() initial-n1 [cat:nom]![cat:nom]-{-n1.1 type:subst [cat:nom]![cat:nom]-n1.2 [cat:cdn]![cat:cdn]-{-n1.2.1 anchor-n1.2.2 type:subst [cat:nom]![cat:nom]-}-}--adj() initial-n1 anchor--{-}--adj_substantif() initial-n1 [cat:nom]![cat:nom]-{-n1.1 anchor-}--adv_adj() auxiliary-n1 [cat:adj]![cat:adj]-{-n1.1 anchor-n1.2 type:foot [cat:adj]![cat:adj]-}--adj_n() auxiliary-n1 [cat:nom]![cat:nom]-{-n1.1 anchor-n1.2 type:foot [cat:nom]![cat:nom]-}--n_adj() auxiliary-n1 [cat:nom]![cat:nom]-{-n1.1 type:foot [cat:nom]![cat:nom]-n1.2 anchor-}--n_gp() auxiliary-n1 [cat:nom]![cat:nom]-{-n1.1 type:foot [cat:nom]![cat:nom]-n1.2 [cat:gp]![cat:gp]-{-n1.2.1 anchor-n1.2.2 type:subst [cat:nom]![cat:nom]-}-}--s_gp() auxiliary-n1 [cat:sen]![cat:sen]-{-n1.1 type:foot [cat:sen]![cat:sen]-n1.2 [cat:gp]![cat:gp]-{-n1.2.1 anchor-n1.2.2 type:subst [cat:nom]![cat:nom]-}-}--gp_s() auxiliary-n1 [cat:sen]![cat:sen]-{-n1.1 type:foot [cat:sen]![cat:sen]-n1.2 [cat:gp]![cat:gp]-{-n1.2.1 anchor-n1.2.2 type:subst [cat:nom]![cat:nom]-}-}--gp() initial-n1 [cat:gp]![cat:gp]-{-n1.1 anchor-n1.2 type:subst [cat:nom]![cat:nom]-}--gpro() initial-n1 [cat:nom]![cat:nom]-{-n1.1 anchor-n1.2 type:subst [cat:nom]![cat:nom]-}--gpro_n_right() auxiliary-n1 [cat:nom]![cat:nom]-{-n1.1 type:foot [cat:nom]![cat:nom]-n1.2 anchor-n1.3 type:subst [cat:nom]![cat:nom]-}--n0_v() initial-n1 [cat:sen]![cat:sen]-{-n1.1 type:subst [cat:nom]![cat:nom]-n1.2 anchor-}--n0_v_n1() initial-n1 [cat:sen]![cat:sen]-{-n1.1 type:subst [cat:nom]![cat:nom]-n1.2 anchor-n1.3 type:subst [cat:nom]![cat:nom]-}--pro_v() initial-n1 [cat:sen]![cat:sen]-{-n1.1 type:subst [cat:pro]![cat:pro]-n1.2 anchor-}--pro_v_n1() initial-n1 [cat:sen]![cat:sen]-{-n1.1 type:subst [cat:pro]![cat:pro]-n1.2 anchor-n1.3 type:subst [cat:nom]![cat:nom]-}--v_inf() initial-n1 [cat:sen]![cat:sen]-{-n1.1 anchor-}--v_n1_inf() initial-n1 [cat:sen]![cat:sen]-{-n1.1 anchor-n1.2 type:subst [cat:nom]![cat:nom]-}--n0_v_s() initial-n1 [cat:sen]![cat:sen]-{-n1.1 type:subst [cat:nom]![cat:nom]-n1.2 anchor-n1.3 type:subst [cat:sen]![cat:sen]-}--pro_v_s() initial-n1 [cat:sen]![cat:sen]-{-n1.1 type:subst [cat:pro]![cat:pro]-n1.2 anchor-n1.3 type:subst [cat:sen]![cat:sen]-}--mod_v() auxiliary-n1 [cat:ver]![cat:ver]-{-n1.1 anchor-n1.2 type:foot [cat:ver]![cat:ver]-}--il_faut_n0() initial-n1 [cat:sen]![cat:sen]-{-n1.1 type:lex "il"-n1.2 anchor-n1.3 type:subst [cat:nom]![cat:nom]-}--mod_pro_left() auxiliary-n1 [cat:ver]![cat:ver]-{-n1.1 anchor-n1.2 type:foot [cat:ver]![cat:ver]-}--qu_est_ce_que() initial-n1 [cat:sen]![cat:sen]-{-n1.1 anchor-n1.2 type:subst [cat:sen]![cat:sen]-}--v_pro() initial-n1 [cat:sen]![cat:sen]-{-n1.1 anchor-n1.2 type:subst [cat:pro]![cat:pro]-}--v_pro_n() initial-n1 [cat:sen]![cat:sen]-{-n1.1 anchor-n1.2 type:subst [cat:pro]![cat:pro]-n1.3 type:subst [cat:nom]![cat:nom]-}--v_pro_s() initial-n1 [cat:sen]![cat:sen]-{-n1.1 anchor-n1.2 type:subst [cat:pro]![cat:pro]-n1.3 type:subst [cat:sen]![cat:sen]-}--mod_adv_left() auxiliary-n1 [cat:ver]![cat:ver]-{-n1.1 anchor-n1.2 type:foot [cat:ver]![cat:ver]-}--mod_adv_right() auxiliary-n1 [cat:ver]![cat:ver]-{-n1.1 type:foot [cat:ver]![cat:ver]-n1.2 anchor-}--mod_adv() auxiliary-n1 [cat:adv]![cat:adv]-{-n1.1 anchor-n1.2 type:foot [cat:adv]![cat:adv]-}--mod_adv_n_left() auxiliary-n1 [cat:nom]![cat:nom]-{-n1.1 type:foot [cat:nom]![cat:nom]-n1.2 anchor-}--mod_adv_n_right() auxiliary-n1 [cat:nom]![cat:nom]-{-n1.1 anchor-n1.2 type:foot [cat:nom]![cat:nom]-}--adv() initial-n1 anchor--{-}--entre_np_et_np() initial-n1 [cat:gp]![cat:gp]-{-n1.1 anchor-n1.2 type:subst [cat:nompropre]![cat:nompropre]-n1.3 type:lex "et"-n1.4 type:subst [cat:nompropre]![cat:nompropre]-}--int() initial-n1 anchor--{-}-
+ examples/nosemantics/trees view
@@ -0,0 +1,363 @@+%%+%% GENI Macro+%% This macro was automatically generated by+%% a tagml->macro script, tagml2genimacro.xsl+%% 2005+%% contact: kow@loria.fr lai@loria.fr++n() initial+n1 anchor++{+}++pro() initial+n1 anchor++{+}++pro_substantif() initial+n1 [cat:nom]![cat:nom]+{+n1.1 anchor+}++det_n() auxiliary+n1 [cat:nom]![cat:nom]+{+n1.1 anchor+n1.2 type:foot [cat:nom]![cat:nom]+}++n_la() auxiliary+n1 [cat:nom]![cat:nom]+{+n1.1 type:foot [cat:nom]![cat:nom]+n1.2 anchor+}++det_substantif() initial+n1 [cat:nom]![cat:nom]+{+n1.1 anchor+}++det_det() auxiliary+n1 [cat:det]![cat:det]+{+n1.1 type:foot [cat:det]![cat:det]+n1.2 anchor+}++np() initial+n1 anchor++{+}++np_substantif() initial+n1 [cat:nom]![cat:nom]+{+n1.1 anchor+}++n_np() auxiliary+n1 [cat:nom]![cat:nom]+{+n1.1 type:foot [cat:nom]![cat:nom]+n1.2 anchor+}++n_con_n() initial+n1 [cat:nom]![cat:nom]+{+n1.1 type:subst [cat:nom]![cat:nom]+n1.2 anchor+n1.3 type:subst [cat:nom]![cat:nom]+}++enum_n() auxiliary+n1 [cat:nom]![cat:nom]+{+n1.1 type:foot [cat:nom]![cat:nom]+n1.2 anchor+}++n_pred() initial+n1 [cat:nom]![cat:nom]+{+n1.1 type:subst [cat:nom]![cat:nom]+n1.2 [cat:gp]![cat:gp]+{+n1.2.1 anchor+n1.2.2 type:subst [cat:nom]![cat:nom]+}+}++compl_n() initial+n1 [cat:nom]![cat:nom]+{+n1.1 type:subst [cat:nom]![cat:nom]+n1.2 [cat:cdn]![cat:cdn]+{+n1.2.1 anchor+n1.2.2 type:subst [cat:nom]![cat:nom]+}+}++adj() initial+n1 anchor++{+}++adj_substantif() initial+n1 [cat:nom]![cat:nom]+{+n1.1 anchor+}++adv_adj() auxiliary+n1 [cat:adj]![cat:adj]+{+n1.1 anchor+n1.2 type:foot [cat:adj]![cat:adj]+}++adj_n() auxiliary+n1 [cat:nom]![cat:nom]+{+n1.1 anchor+n1.2 type:foot [cat:nom]![cat:nom]+}++n_adj() auxiliary+n1 [cat:nom]![cat:nom]+{+n1.1 type:foot [cat:nom]![cat:nom]+n1.2 anchor+}++n_gp() auxiliary+n1 [cat:nom]![cat:nom]+{+n1.1 type:foot [cat:nom]![cat:nom]+n1.2 [cat:gp]![cat:gp]+{+n1.2.1 anchor+n1.2.2 type:subst [cat:nom]![cat:nom]+}+}++s_gp() auxiliary+n1 [cat:sen]![cat:sen]+{+n1.1 type:foot [cat:sen]![cat:sen]+n1.2 [cat:gp]![cat:gp]+{+n1.2.1 anchor+n1.2.2 type:subst [cat:nom]![cat:nom]+}+}++gp_s() auxiliary+n1 [cat:sen]![cat:sen]+{+n1.1 type:foot [cat:sen]![cat:sen]+n1.2 [cat:gp]![cat:gp]+{+n1.2.1 anchor+n1.2.2 type:subst [cat:nom]![cat:nom]+}+}++gp() initial+n1 [cat:gp]![cat:gp]+{+n1.1 anchor+n1.2 type:subst [cat:nom]![cat:nom]+}++gpro() initial+n1 [cat:nom]![cat:nom]+{+n1.1 anchor+n1.2 type:subst [cat:nom]![cat:nom]+}++gpro_n_right() auxiliary+n1 [cat:nom]![cat:nom]+{+n1.1 type:foot [cat:nom]![cat:nom]+n1.2 anchor+n1.3 type:subst [cat:nom]![cat:nom]+}++n0_v() initial+n1 [cat:sen]![cat:sen]+{+n1.1 type:subst [cat:nom]![cat:nom]+n1.2 anchor+}++n0_v_n1() initial+n1 [cat:sen]![cat:sen]+{+n1.1 type:subst [cat:nom]![cat:nom]+n1.2 anchor+n1.3 type:subst [cat:nom]![cat:nom]+}++pro_v() initial+n1 [cat:sen]![cat:sen]+{+n1.1 type:subst [cat:pro]![cat:pro]+n1.2 anchor+}++pro_v_n1() initial+n1 [cat:sen]![cat:sen]+{+n1.1 type:subst [cat:pro]![cat:pro]+n1.2 anchor+n1.3 type:subst [cat:nom]![cat:nom]+}++v_inf() initial+n1 [cat:sen]![cat:sen]+{+n1.1 anchor+}++v_n1_inf() initial+n1 [cat:sen]![cat:sen]+{+n1.1 anchor+n1.2 type:subst [cat:nom]![cat:nom]+}++n0_v_s() initial+n1 [cat:sen]![cat:sen]+{+n1.1 type:subst [cat:nom]![cat:nom]+n1.2 anchor+n1.3 type:subst [cat:sen]![cat:sen]+}++pro_v_s() initial+n1 [cat:sen]![cat:sen]+{+n1.1 type:subst [cat:pro]![cat:pro]+n1.2 anchor+n1.3 type:subst [cat:sen]![cat:sen]+}++mod_v() auxiliary+n1 [cat:ver]![cat:ver]+{+n1.1 anchor+n1.2 type:foot [cat:ver]![cat:ver]+}++il_faut_n0() initial+n1 [cat:sen]![cat:sen]+{+n1.1 type:lex "il"+n1.2 anchor+n1.3 type:subst [cat:nom]![cat:nom]+}++mod_pro_left() auxiliary+n1 [cat:ver]![cat:ver]+{+n1.1 anchor+n1.2 type:foot [cat:ver]![cat:ver]+}++qu_est_ce_que() initial+n1 [cat:sen]![cat:sen]+{+n1.1 anchor+n1.2 type:subst [cat:sen]![cat:sen]+}++v_pro() initial+n1 [cat:sen]![cat:sen]+{+n1.1 anchor+n1.2 type:subst [cat:pro]![cat:pro]+}++v_pro_n() initial+n1 [cat:sen]![cat:sen]+{+n1.1 anchor+n1.2 type:subst [cat:pro]![cat:pro]+n1.3 type:subst [cat:nom]![cat:nom]+}++v_pro_s() initial+n1 [cat:sen]![cat:sen]+{+n1.1 anchor+n1.2 type:subst [cat:pro]![cat:pro]+n1.3 type:subst [cat:sen]![cat:sen]+}++mod_adv_left() auxiliary+n1 [cat:ver]![cat:ver]+{+n1.1 anchor+n1.2 type:foot [cat:ver]![cat:ver]+}++mod_adv_right() auxiliary+n1 [cat:ver]![cat:ver]+{+n1.1 type:foot [cat:ver]![cat:ver]+n1.2 anchor+}++mod_adv() auxiliary+n1 [cat:adv]![cat:adv]+{+n1.1 anchor+n1.2 type:foot [cat:adv]![cat:adv]+}++mod_adv_n_left() auxiliary+n1 [cat:nom]![cat:nom]+{+n1.1 type:foot [cat:nom]![cat:nom]+n1.2 anchor+}++mod_adv_n_right() auxiliary+n1 [cat:nom]![cat:nom]+{+n1.1 anchor+n1.2 type:foot [cat:nom]![cat:nom]+}++adv() initial+n1 anchor++{+}++entre_np_et_np() initial+n1 [cat:gp]![cat:gp]+{+n1.1 anchor+n1.2 type:subst [cat:nompropre]![cat:nompropre]+n1.3 type:lex "et"+n1.4 type:subst [cat:nompropre]![cat:nompropre]+}++int() initial+n1 anchor++{+}+
− examples/promettre/macros
@@ -1,450 +0,0 @@-%% 02 april 2004-%% 1. Jean promet un cadeau a Marie-%% 2. Jean promet a Marie de partir-%% 6. la personne qui promet un cadeau a Marie-%% 7. le cadeau que Jean promet a Marie-%% 8. la personne a qui Jean promet un cadeau-%% 9. promettre un cadeau a Marie-%% 10. promettant un cadeau a Marie-%% 11. donner un livre a marie--% FIXME: eric the non-linguist set all cat:p nodes with unspecified mode to FIXME--Det(?I) auxiliary-n1[cat:n idx:?I det:plus qu:minus]![cat:n idx:?I qu:minus]-{- n2 type:anchor [cat:det]![]- n4 type:foot [cat:n idx:?I]![cat:n idx:?I det:minus]-}--clitic:cl(?H ?X ! idx:?X ) initial-n1 type:anchor [cat:cl idx:?X]![cat:cl idx:?X] {}--pronoun:pn(?H ?X ! idx:?X num:?Num gen:?Gen pers:?Pers) initial-n1 [cat:n idx:?X num:?Num gen:?Gen pers:?Pers]![cat:n idx:?X]-{- n2 type:anchor [cat:pn num:?Num gen:?Gen pers:?Pers]![] -}--% Common Nouns: voyage-nC(?I!num:?Num gen:?Gen) initial-n1 [cat:n num:?Num gen:?Gen idx:?I]![cat:n num:?Num gen:?Gen idx:?I det:minus qu:minus]-{- n2 type:anchor [cat:n num:?Num gen:?Gen]![]-}--% Proper Nouns: Jean-nP(?I!pers:?Pers num:?Num gen:?Gen) initial-n1 type:anchor [cat:n num:?Num pers:?Pers gen:?Gen idx:?I det:plus qu:minus]![cat:n idx:?I det:plus qu:minus] {}----% jean se aimer -- note: we rely on top/bottom unification-% for this to work-vArity2:n0v(?E ?X ?Y) initial -n1[cat:p mode:FIXME]![]-{- n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?Y]- n5 [cat:se idx:?X det:plus qu:minus]![cat:se idx:?Y]- n3 type:anchor [cat:v idx:?E]![]-}--vArity2:n0cl1v(?E ?X ?Y) initial-n1[cat:p mode:FIXME]![]-{- n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X]- n5 type:subst [cat:cl idx:?Y det:plus qu:minus]![cat:cl idx:?Y]- n3 type:anchor [cat:v idx:?E]![]-}--vArity2:n0vn1(?E ?X ?Y) initial-n1[cat:p mode:FIXME]![]-{- n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X]- n3 type:anchor [cat:v idx:?E]![]- n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]-} --% aimer N (jean espere [aimer Marie])-vArity2:vinfn1(?E ?X ?Y) initial -n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p]-{- n2 type:anchor [cat:v idx:?E]![]- n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]-}--% le aimer (jean espere [le aimer])-cl0vinf(?E ?X ?Y) initial -n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p]-{- n5 type:subst [cat:cl idx:?Y det:plus qu:minus]![cat:cl idx:?Y]- n2 type:anchor [cat:v idx:?E]![]-}--% infinitive: le donner un livre (je promets de le donner un livre)-vArity3:cl2vinfn0(?E ?X ?Y ?Z) initial -n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p]-{- n5 type:subst [cat:cl idx:?Z det:plus qu:minus]![cat:cl idx:?Z]- n2 type:anchor [cat:v idx:?E]![]- n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]-} -- %1 declarative gn promet gn sp_a-vArity3:n0vn1sp2(?E ?X ?Y ?Z) initial-n1[cat:p mode:FIXME]![]-{- n2 type:subst [cat:n pers:?Pers num:?Num idx:?X det:plus qu:minus]![cat:n idx:?X]- n3[cat:v idx:?E]![]- {- n4 type:anchor [cat:v pers:?Pers num:?Num]![] - }- n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]- n6[cat:sp idx:?Z det:plus]![]- { n8[cat:prep]![]- {- n9 type:lex "a"- }- n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] - }-}--- %2 infinitive ?V GN SP_a-vArity3:vinfn1sp2(?E ?X ?Y ?Z) initial-n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p]-{- n2 type:anchor [cat:v idx:?E]![]- n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]- n5[cat:sp idx:?Z det:plus]![]- { n6[cat:prep]![]- {- n7 type:lex "a"- }- n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] - }-}--vArity3:n0vn1inf2(?E ?X ?Y ?Z) initial-n1[cat:p mode:FIXME]![]-{- n2 type:subst [cat:n idx:?X pers:?Pers num:?Num det:plus qu:minus]![cat:n idx:?X]- n3[cat:v idx:?E]![]- {- n4 type:anchor [cat:v pers:?Pers num:?Num]![] - }- n5[cat:sp idx:?Z det:plus]![]- { n6[cat:p]![]- {- n7 type:lex "a"- }- n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z- ] - }- n9 type:subst [cat:p idx:?Y mode:inf]![cat:p idx:?Y] -}--%8 relative objet indirect-vArity3:rel2n0vn1(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?Z det:plus]![cat:n idx:?Z]-{- n1 type:foot [cat:n idx:?Z]![cat:n idx:?Z]- n2[cat:p]![]- {- n3[cat:sp idx:?Z det:plus]![]- { n4[cat:prep]![]- {- n5 type:lex "a"- }- n6 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z qu:plus] - }- n7[cat:p idx:?E]![]- {- n8 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X qu:minus]- n9 type:anchor [cat:v idx:?E]![cat:p idx:?E]- n11 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]- }- }-}-- %9 declarative GN V GN_a Pinf_de-vArity3control:n0vsp2pinf1(?E ?X ?Y ?Z) initial-n1[cat:p mode:FIXME]![]-{- n2 type:subst [cat:n pers:?Pers num:?Num idx:?X det:plus qu:minus]![cat:n idx:?X]- n3[cat:v idx:?E]![]- {- n4 type:anchor [cat:v pers:?Pers num:?Num]![]- }- n5[cat:sp idx:?Z det:plus]![]- { n6[cat:prep]![]- {- n7 type:lex "a"- }- n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] - }- n9[cat:p]![]- {n10[cat:prep]![]- {- n11 type:lex "de"- } - n12 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y]- }-}-- %10 infinitive V SP_a Inf_de-vArity3control:vinfsp2pinf1(?E ?X ?Y ?Z) initial-n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p] -{- n2 type:anchor [cat:v idx:?E]![]- n4[cat:sp idx:?Y det:plus]![]- { n5[cat:prep]![]- {- n6 type:lex "a"- }- n7 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y- ] - }- n8[cat:p]![]- {n9[cat:prep]![]- {- n10 type:lex "de"- } - n11 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y]-- }-}-- % kowey: promettre a marie de faire...-vArity3control:vinfn2pinf1(?E ?X ?Y ?Z) initial-n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p] -{- n2 type:anchor [cat:v idx:?E]![]-- n5[cat:sp idx:?Z det:plus]![]- { n6[cat:prep]![]- {- n7 type:lex "a"- }- n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] - }-- n10[cat:p]![]- {n11[cat:prep]![]- {- n12 type:lex "de"- } - n13 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y]- }-}-- %13 relative sujet qui V sp_a pinf_de-vArity3control:rel0vsp2pinf1(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?X det:plus]![cat:n idx:?X]-{- n1 type:foot [cat:n idx:?X]![cat:n idx:?X]- n2[cat:p]![]- {- n3 type:subst [cat:cl idx:?X det:plus qu:minus]![cat:cl idx:?X]- n4 type:anchor [cat:v idx:?E]![]- n6[cat:sp idx:?Y]![]- { n7[cat:prep]![]- {- n8 type:lex "a"- }- n9 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n - ] - }- n10[cat:p]![]- {n11[cat:prep]![]- {- n12 type:lex "de"- } - n13 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y]- }}}---%14 relative objet indirect a qui GN v Pinf_de-vArity3control:rel2n0vpinf1(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?Y det:plus]![cat:n idx:?Y]-{- n1 type:foot [cat:n idx:?Y]![cat:n idx:?Y]- n2[cat:p]![]- {- n3[cat:sp idx:?Y det:plus]![]- { n4[cat:prep]![]- {- n5 type:lex "a"- }- n6 type:subst [cat:n idx:?Y det:plus qu:plus]![cat:n idx:?Y qu:plus] - }- n7[cat:p idx:?E]![]- {- n8 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X qu:minus]- n9 type:anchor [cat:v idx:?E]![cat:p idx:?E]- }- n9[cat:p]![]- {n10[cat:prep]![]- {- n11 type:lex "de"- } - n12 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z]- }- }}---vArity3control:rel0vn2pinf1(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?X det:plus]![cat:n idx:?X]-{- n1 type:foot [cat:n idx:?X]![cat:n idx:?X]- n2[cat:p]![]- {- n3 type:subst [cat:cl idx:?X det:plus qu:minus]![cat:n idx:?X]- n4 type:anchor [cat:v idx:?E]![]- n6 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n - ] - n7[cat:p]![]- {n8[cat:prep]![]- {- n9 type:lex "de"- } - n10 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z]- }}}--% relative sujet-vArity3control:rel0vn1sp2(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?X det:plus]![cat:n idx:?X]-{- n1 type:foot [cat:n idx:?X]![cat:n idx:?X]- n2[cat:p]![]- {- n3 type:subst [cat:cl idx:?X det:plus qu:minus]![cat:n idx:?X]- n4 type:anchor [cat:v idx:?E]![]- n6 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z]- n7[cat:sp idx:?Y]![]- { n8[cat:p]![]- {- n9 type:lex "a"- }- n10 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n] - }- }-}--% relative objet-vArity3control:rel1vn0sp2(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?X det:plus]![cat:n idx:?X]-{- n1 type:foot [cat:n idx:?X]![cat:n idx:?X]- n2[cat:p]![]- {- n3 type:subst [cat:cl idx:?X det:plus qu:minus]![cat:cl idx:?X]- n4 type:anchor [cat:v idx:?E]![]- n6 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z]- n7[cat:sp idx:?Y]![]- { n8[cat:p]![]- {- n9 type:lex "a"- }- n10 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n] - }- }-}-- % relative objet indirect-rel2vn0n1(?E ?X ?Y ?Z) auxiliary-n0[cat:n idx:?Y det:plus]![cat:n idx:?Y]-{- n1 type:foot [cat:n idx:?Y]![cat:n idx:?Y]- n2[cat:p]![]- {- n3[cat:sp idx:?Y det:plus]![]- { n4[cat:p]![]- {- n5 type:lex "a"- }- n6 type:subst [cat:n idx:?Y det:plus qu:plus]![cat:n idx:?Y qu:plus] - }- n7[cat:p idx:?E]![]- {- n8 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X qu:minus]- n9 type:anchor [cat:v idx:?E]![cat:p idx:?E]- n11 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z]- }- }-}-- % kowey: for persuader instead of promettre- % (sujidx is set differently)-vArity3controlObj:n0vsp2pinf1b(?E ?X ?Y ?Z) initial-n1[cat:p mode:FIXME]![]-{- n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X]- n3 type:anchor [cat:v idx:?E]![]- n5[cat:sp idx:?Z det:plus]![]- { n6[cat:prep]![]- {- n7 type:lex "a"- }- n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] - }- n9[cat:p]![]- {n10[cat:prep]![]- {- n11 type:lex "de"- } - n12 type:subst [cat:p idx:?Y mode:inf sujidx:?Z]![cat:p idx:?Y]- }-}-- %15 declarative gn0 persuade gn2 pinf_de1 n0vn2pinf1 -vArity3controlObj:n0vn2pinf1b(?E ?X ?Y ?Z) initial-n1[cat:p mode:FIXME]![]-{- n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X]- n3 type:anchor [cat:v idx:?E]![]- n5 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z]- n6[cat:p]![]- {n7[cat:prep]![]- {- n8 type:lex "de"- } - n9 type:subst [cat:p idx:?Y mode:inf sujidx:?Z]![cat:p idx:?Y] - }-}-- %15 infinitive persuader gn pinf_de vinfn2pinf1-vArity3controlObj:vinfn2pinf1b(?E ?X ?Y ?Z) initial-n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p] -{- n2 type:anchor [cat:v idx:?E]![]- n4 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] - n5[cat:p]![]- {n6[cat:prep]![]- {- n7 type:lex "de"- } - n8 type:subst [cat:p idx:?Y mode:inf sujidx:?Z]![cat:p idx:?Y]- }-}-- %18 rel-sjt n qui persuade gn pinf_de rel0vn2pinf1-vArity3controlObj:n0vn1sp2(?E ?X ?Y ?Z) initial-n1[cat:p mode:FIXME]![]-{- n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X]- n3 type:anchor [cat:v idx:?E]![]- n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]- n6[cat:sp idx:?Z det:plus]![]- { n8[cat:p]![]- {- n9 type:lex "a"- }- n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z- ] - }-}--% vi: set cinoptions=0,p0:--
+ examples/promettre/trees view
@@ -0,0 +1,450 @@+%% 02 april 2004+%% 1. Jean promet un cadeau a Marie+%% 2. Jean promet a Marie de partir+%% 6. la personne qui promet un cadeau a Marie+%% 7. le cadeau que Jean promet a Marie+%% 8. la personne a qui Jean promet un cadeau+%% 9. promettre un cadeau a Marie+%% 10. promettant un cadeau a Marie+%% 11. donner un livre a marie++% FIXME: eric the non-linguist set all cat:p nodes with unspecified mode to FIXME++Det(?I) auxiliary+n1[cat:n idx:?I det:plus qu:minus]![cat:n idx:?I qu:minus]+{+ n2 type:anchor [cat:det]![]+ n4 type:foot [cat:n idx:?I]![cat:n idx:?I det:minus]+}++clitic:cl(?H ?X ! idx:?X ) initial+n1 type:anchor [cat:cl idx:?X]![cat:cl idx:?X] {}++pronoun:pn(?H ?X ! idx:?X num:?Num gen:?Gen pers:?Pers) initial+n1 [cat:n idx:?X num:?Num gen:?Gen pers:?Pers]![cat:n idx:?X]+{+ n2 type:anchor [cat:pn num:?Num gen:?Gen pers:?Pers]![] +}++% Common Nouns: voyage+nC(?I!num:?Num gen:?Gen) initial+n1 [cat:n num:?Num gen:?Gen idx:?I]![cat:n num:?Num gen:?Gen idx:?I det:minus qu:minus]+{+ n2 type:anchor [cat:n num:?Num gen:?Gen]![]+}++% Proper Nouns: Jean+nP(?I!pers:?Pers num:?Num gen:?Gen) initial+n1 type:anchor [cat:n num:?Num pers:?Pers gen:?Gen idx:?I det:plus qu:minus]![cat:n idx:?I det:plus qu:minus] {}++++% jean se aimer -- note: we rely on top/bottom unification+% for this to work+vArity2:n0v(?E ?X ?Y) initial +n1[cat:p mode:FIXME]![]+{+ n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?Y]+ n5 [cat:se idx:?X det:plus qu:minus]![cat:se idx:?Y]+ n3 type:anchor [cat:v idx:?E]![]+}++vArity2:n0cl1v(?E ?X ?Y) initial+n1[cat:p mode:FIXME]![]+{+ n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X]+ n5 type:subst [cat:cl idx:?Y det:plus qu:minus]![cat:cl idx:?Y]+ n3 type:anchor [cat:v idx:?E]![]+}++vArity2:n0vn1(?E ?X ?Y) initial+n1[cat:p mode:FIXME]![]+{+ n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X]+ n3 type:anchor [cat:v idx:?E]![]+ n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]+} ++% aimer N (jean espere [aimer Marie])+vArity2:vinfn1(?E ?X ?Y) initial +n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p]+{+ n2 type:anchor [cat:v idx:?E]![]+ n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]+}++% le aimer (jean espere [le aimer])+cl0vinf(?E ?X ?Y) initial +n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p]+{+ n5 type:subst [cat:cl idx:?Y det:plus qu:minus]![cat:cl idx:?Y]+ n2 type:anchor [cat:v idx:?E]![]+}++% infinitive: le donner un livre (je promets de le donner un livre)+vArity3:cl2vinfn0(?E ?X ?Y ?Z) initial +n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p]+{+ n5 type:subst [cat:cl idx:?Z det:plus qu:minus]![cat:cl idx:?Z]+ n2 type:anchor [cat:v idx:?E]![]+ n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]+} ++ %1 declarative gn promet gn sp_a+vArity3:n0vn1sp2(?E ?X ?Y ?Z) initial+n1[cat:p mode:FIXME]![]+{+ n2 type:subst [cat:n pers:?Pers num:?Num idx:?X det:plus qu:minus]![cat:n idx:?X]+ n3[cat:v idx:?E]![]+ {+ n4 type:anchor [cat:v pers:?Pers num:?Num]![] + }+ n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]+ n6[cat:sp idx:?Z det:plus]![]+ { n8[cat:prep]![]+ {+ n9 type:lex "a"+ }+ n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] + }+}+++ %2 infinitive ?V GN SP_a+vArity3:vinfn1sp2(?E ?X ?Y ?Z) initial+n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p]+{+ n2 type:anchor [cat:v idx:?E]![]+ n4 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]+ n5[cat:sp idx:?Z det:plus]![]+ { n6[cat:prep]![]+ {+ n7 type:lex "a"+ }+ n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] + }+}++vArity3:n0vn1inf2(?E ?X ?Y ?Z) initial+n1[cat:p mode:FIXME]![]+{+ n2 type:subst [cat:n idx:?X pers:?Pers num:?Num det:plus qu:minus]![cat:n idx:?X]+ n3[cat:v idx:?E]![]+ {+ n4 type:anchor [cat:v pers:?Pers num:?Num]![] + }+ n5[cat:sp idx:?Z det:plus]![]+ { n6[cat:p]![]+ {+ n7 type:lex "a"+ }+ n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z+ ] + }+ n9 type:subst [cat:p idx:?Y mode:inf]![cat:p idx:?Y] +}++%8 relative objet indirect+vArity3:rel2n0vn1(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?Z det:plus]![cat:n idx:?Z]+{+ n1 type:foot [cat:n idx:?Z]![cat:n idx:?Z]+ n2[cat:p]![]+ {+ n3[cat:sp idx:?Z det:plus]![]+ { n4[cat:prep]![]+ {+ n5 type:lex "a"+ }+ n6 type:subst [cat:n idx:?Z det:plus qu:plus]![cat:n idx:?Z qu:plus] + }+ n7[cat:p idx:?E]![]+ {+ n8 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X qu:minus]+ n9 type:anchor [cat:v idx:?E]![cat:p idx:?E]+ n11 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]+ }+ }+}++ %9 declarative GN V GN_a Pinf_de+vArity3control:n0vsp2pinf1(?E ?X ?Y ?Z) initial+n1[cat:p mode:FIXME]![]+{+ n2 type:subst [cat:n pers:?Pers num:?Num idx:?X det:plus qu:minus]![cat:n idx:?X]+ n3[cat:v idx:?E]![]+ {+ n4 type:anchor [cat:v pers:?Pers num:?Num]![]+ }+ n5[cat:sp idx:?Z det:plus]![]+ { n6[cat:prep]![]+ {+ n7 type:lex "a"+ }+ n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] + }+ n9[cat:p]![]+ {n10[cat:prep]![]+ {+ n11 type:lex "de"+ } + n12 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y]+ }+}++ %10 infinitive V SP_a Inf_de+vArity3control:vinfsp2pinf1(?E ?X ?Y ?Z) initial+n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p] +{+ n2 type:anchor [cat:v idx:?E]![]+ n4[cat:sp idx:?Y det:plus]![]+ { n5[cat:prep]![]+ {+ n6 type:lex "a"+ }+ n7 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y+ ] + }+ n8[cat:p]![]+ {n9[cat:prep]![]+ {+ n10 type:lex "de"+ } + n11 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y]++ }+}++ % kowey: promettre a marie de faire...+vArity3control:vinfn2pinf1(?E ?X ?Y ?Z) initial+n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p] +{+ n2 type:anchor [cat:v idx:?E]![]++ n5[cat:sp idx:?Z det:plus]![]+ { n6[cat:prep]![]+ {+ n7 type:lex "a"+ }+ n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] + }++ n10[cat:p]![]+ {n11[cat:prep]![]+ {+ n12 type:lex "de"+ } + n13 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y]+ }+}++ %13 relative sujet qui V sp_a pinf_de+vArity3control:rel0vsp2pinf1(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?X det:plus]![cat:n idx:?X]+{+ n1 type:foot [cat:n idx:?X]![cat:n idx:?X]+ n2[cat:p]![]+ {+ n3 type:subst [cat:cl idx:?X det:plus qu:minus]![cat:cl idx:?X]+ n4 type:anchor [cat:v idx:?E]![]+ n6[cat:sp idx:?Y]![]+ { n7[cat:prep]![]+ {+ n8 type:lex "a"+ }+ n9 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n + ] + }+ n10[cat:p]![]+ {n11[cat:prep]![]+ {+ n12 type:lex "de"+ } + n13 type:subst [cat:p idx:?Y mode:inf sujidx:?X]![cat:p idx:?Y]+ }}}+++%14 relative objet indirect a qui GN v Pinf_de+vArity3control:rel2n0vpinf1(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?Y det:plus]![cat:n idx:?Y]+{+ n1 type:foot [cat:n idx:?Y]![cat:n idx:?Y]+ n2[cat:p]![]+ {+ n3[cat:sp idx:?Y det:plus]![]+ { n4[cat:prep]![]+ {+ n5 type:lex "a"+ }+ n6 type:subst [cat:n idx:?Y det:plus qu:plus]![cat:n idx:?Y qu:plus] + }+ n7[cat:p idx:?E]![]+ {+ n8 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X qu:minus]+ n9 type:anchor [cat:v idx:?E]![cat:p idx:?E]+ }+ n9[cat:p]![]+ {n10[cat:prep]![]+ {+ n11 type:lex "de"+ } + n12 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z]+ }+ }}+++vArity3control:rel0vn2pinf1(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?X det:plus]![cat:n idx:?X]+{+ n1 type:foot [cat:n idx:?X]![cat:n idx:?X]+ n2[cat:p]![]+ {+ n3 type:subst [cat:cl idx:?X det:plus qu:minus]![cat:n idx:?X]+ n4 type:anchor [cat:v idx:?E]![]+ n6 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n + ] + n7[cat:p]![]+ {n8[cat:prep]![]+ {+ n9 type:lex "de"+ } + n10 type:subst [cat:p idx:?Z mode:inf sujidx:?X]![cat:p idx:?Z]+ }}}++% relative sujet+vArity3control:rel0vn1sp2(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?X det:plus]![cat:n idx:?X]+{+ n1 type:foot [cat:n idx:?X]![cat:n idx:?X]+ n2[cat:p]![]+ {+ n3 type:subst [cat:cl idx:?X det:plus qu:minus]![cat:n idx:?X]+ n4 type:anchor [cat:v idx:?E]![]+ n6 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z]+ n7[cat:sp idx:?Y]![]+ { n8[cat:p]![]+ {+ n9 type:lex "a"+ }+ n10 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n] + }+ }+}++% relative objet+vArity3control:rel1vn0sp2(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?X det:plus]![cat:n idx:?X]+{+ n1 type:foot [cat:n idx:?X]![cat:n idx:?X]+ n2[cat:p]![]+ {+ n3 type:subst [cat:cl idx:?X det:plus qu:minus]![cat:cl idx:?X]+ n4 type:anchor [cat:v idx:?E]![]+ n6 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z]+ n7[cat:sp idx:?Y]![]+ { n8[cat:p]![]+ {+ n9 type:lex "a"+ }+ n10 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n] + }+ }+}++ % relative objet indirect+rel2vn0n1(?E ?X ?Y ?Z) auxiliary+n0[cat:n idx:?Y det:plus]![cat:n idx:?Y]+{+ n1 type:foot [cat:n idx:?Y]![cat:n idx:?Y]+ n2[cat:p]![]+ {+ n3[cat:sp idx:?Y det:plus]![]+ { n4[cat:p]![]+ {+ n5 type:lex "a"+ }+ n6 type:subst [cat:n idx:?Y det:plus qu:plus]![cat:n idx:?Y qu:plus] + }+ n7[cat:p idx:?E]![]+ {+ n8 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X qu:minus]+ n9 type:anchor [cat:v idx:?E]![cat:p idx:?E]+ n11 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z]+ }+ }+}++ % kowey: for persuader instead of promettre+ % (sujidx is set differently)+vArity3controlObj:n0vsp2pinf1b(?E ?X ?Y ?Z) initial+n1[cat:p mode:FIXME]![]+{+ n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X]+ n3 type:anchor [cat:v idx:?E]![]+ n5[cat:sp idx:?Z det:plus]![]+ { n6[cat:prep]![]+ {+ n7 type:lex "a"+ }+ n8 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] + }+ n9[cat:p]![]+ {n10[cat:prep]![]+ {+ n11 type:lex "de"+ } + n12 type:subst [cat:p idx:?Y mode:inf sujidx:?Z]![cat:p idx:?Y]+ }+}++ %15 declarative gn0 persuade gn2 pinf_de1 n0vn2pinf1 +vArity3controlObj:n0vn2pinf1b(?E ?X ?Y ?Z) initial+n1[cat:p mode:FIXME]![]+{+ n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X]+ n3 type:anchor [cat:v idx:?E]![]+ n5 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z]+ n6[cat:p]![]+ {n7[cat:prep]![]+ {+ n8 type:lex "de"+ } + n9 type:subst [cat:p idx:?Y mode:inf sujidx:?Z]![cat:p idx:?Y] + }+}++ %15 infinitive persuader gn pinf_de vinfn2pinf1+vArity3controlObj:vinfn2pinf1b(?E ?X ?Y ?Z) initial+n1[cat:p idx:?E mode:inf sujidx:?X]![cat:p] +{+ n2 type:anchor [cat:v idx:?E]![]+ n4 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z] + n5[cat:p]![]+ {n6[cat:prep]![]+ {+ n7 type:lex "de"+ } + n8 type:subst [cat:p idx:?Y mode:inf sujidx:?Z]![cat:p idx:?Y]+ }+}++ %18 rel-sjt n qui persuade gn pinf_de rel0vn2pinf1+vArity3controlObj:n0vn1sp2(?E ?X ?Y ?Z) initial+n1[cat:p mode:FIXME]![]+{+ n2 type:subst [cat:n idx:?X det:plus qu:minus]![cat:n idx:?X]+ n3 type:anchor [cat:v idx:?E]![]+ n5 type:subst [cat:n idx:?Y det:plus qu:minus]![cat:n idx:?Y]+ n6[cat:sp idx:?Z det:plus]![]+ { n8[cat:p]![]+ {+ n9 type:lex "a"+ }+ n10 type:subst [cat:n idx:?Z det:plus qu:minus]![cat:n idx:?Z+ ] + }+}++% vi: set cinoptions=0,p0:++
examples/xmg-example/Makefile view
@@ -15,12 +15,12 @@ SUITE_LEXICON:=$(LEXICON_DIR)/$(FULL_LEXICON_PREFIX).lex SUITE_MORPH:=$(LEXICON_DIR)/$(MORPH_PREFIX).mph -GENI_GRAMMAR:=$(COMPILED_GRAMMAR_DIR)/$(GRAMMAR).genib+GENI_GRAMMAR:=$(COMPILED_GRAMMAR_DIR)/$(GRAMMAR).geni GENI_LEXICON:=$(LEXICON_DIR)/$(FULL_LEXICON_PREFIX).glex GENI_MORPH:=$(LEXICON_DIR)/$(MORPH_PREFIX).gmorph GENI_SUITE:=suite -GENI_OPTIMISATIONS:='pol f-sem'+GENI_OPTIMISATIONS:='pol' GENI_LEX_FLAGS:=-l $(GENI_LEXICON) -s $(GENI_SUITE) ifdef ENABLE_MORPH@@ -59,7 +59,7 @@ NEW_DERIVATIONS:=new-derivations run: $(GENI_GRAMMAR) lexicon morph- $(GENI) -m $< $(GENI_FLAGS) --nogui --batchdir=results+ $(GENI) -m $< $(GENI_FLAGS) --nogui --batchdir=results --rootfeat='[cat:s]' # -------------------------------------------------------------------- # running GenI@@ -109,11 +109,7 @@ %.geni : %.xml $(ECHO_STATUS) "converting to geni text format: $(basename $<)"- $(SILENTLY) geniconvert -f tagml -t geni $< -o $@--%.genib : %.geni- $(ECHO_STATUS) "converting to geni binary format: $<"- $(SILENTLY) geniconvert -f geni -t genib $< -o $@+ $(SILENTLY) xsltproc -o $@ xmg2geni.xsl $< # -------------------------------------------------------------------- # lexicon
+ geni-test/MainTest.hs view
@@ -0,0 +1,5 @@+module Main where++import NLP.GenI.Test++main = runTests
+ geni-test/NLP/GenI/Test.hs view
@@ -0,0 +1,53 @@+-- ----------------------------------------------------------------------+-- GenI surface realiser+-- Copyright (C) 2009 Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.+-- ----------------------------------------------------------------------++module NLP.GenI.Test where++import Data.List ( isPrefixOf )+import System.Environment ( getArgs )++import Test.Framework++import NLP.GenI.Test.FeatureStructure ( suite )+import NLP.GenI.Test.Parser ( suite )+import NLP.GenI.Test.GeniVal ( suite )+import NLP.GenI.Test.LexicalSelection ( suite )+import NLP.GenI.Test.Lexicon ( suite )+import NLP.GenI.Test.Morphology ( suite )+import NLP.GenI.Test.Polarity ( suite )+import NLP.GenI.Test.Semantics ( suite )+import NLP.GenI.Test.Simple.SimpleBuilder ( suite )+import NLP.GenI.Regression++runTests :: IO ()+runTests = do+ args <- filter (not . (`isPrefixOf` "--unit-tests")) `fmap` getArgs+ funcSuite <- NLP.GenI.Regression.mkSuite+ flip defaultMainWithArgs args+ [ NLP.GenI.Test.GeniVal.suite+ , NLP.GenI.Test.Parser.suite+ , NLP.GenI.Test.FeatureStructure.suite+ , NLP.GenI.Test.LexicalSelection.suite+ , NLP.GenI.Test.Lexicon.suite+ , NLP.GenI.Test.Morphology.suite+ , NLP.GenI.Test.Polarity.suite+ , NLP.GenI.Test.Semantics.suite+ , NLP.GenI.Test.Simple.SimpleBuilder.suite+ , funcSuite+ ]
+ geni/geni.hs view
@@ -0,0 +1,20 @@+-- GenI surface realiser+-- Copyright (C) 2005 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++module Main (module NLP.GenI.Main) where++import NLP.GenI.Main
+ src/BoolExp.hs view
@@ -0,0 +1,12 @@+module BoolExp where++data BoolExp a = Cond a+ | And (BoolExp a) (BoolExp a)+ | Or (BoolExp a) (BoolExp a)+ | Not (BoolExp a)++check :: (a -> Bool) -> BoolExp a -> Bool+check f (Cond x) = f x+check f (And x y) = check f x && check f y+check f (Or x y) = check f x || check f y+check f (Not x) = not (check f x)
+ src/Data/FullList.hs view
@@ -0,0 +1,14 @@+{-# OPTIONS_GHC -fno-warn-unused-imports #-}+module Data.FullList+ (FullList,+ fromFL,+ indeedFL,+ head,+ tail,+ (++),+ sortNub,+ Listable (..)+ ) where++import Data.FullList.Internal+import Prelude hiding ( head, tail, (++) )
+ src/Data/FullList/Internal.hs view
@@ -0,0 +1,80 @@+{-# LANGUAGE DeriveDataTypeable #-}++-- from http://www.haskell.org/haskellwiki/Non-empty_list+-- Safe list functions++module Data.FullList.Internal where++import Data.Binary+import Control.DeepSeq+import Prelude hiding (head, tail, (++))+import qualified Prelude+import Data.Data+import Data.List ( sort, nub )++newtype FullList a = FullList [a] -- data constructor is not exported!+ deriving (Eq, Ord, Show, Data, Typeable)++fromFL :: FullList a -> [a]+fromFL (FullList x) = x -- Injection into general lists++-- The following is an analogue of `maybe'+indeedFL :: [a] -> w -> (FullList a -> w) -> w+indeedFL x on_empty on_full+ | null x = on_empty+ | otherwise = on_full $ FullList x++-- The following are _total_ functions+-- They are guaranteed to be safe, and so we could have used+-- unsafeHead# and unsafeTail# if GHC provides though...++head :: FullList a -> a+head (FullList (x:_)) = x+head (FullList _) = error "NList.head is broken"++tail :: FullList a -> [a]+tail (FullList (_:x)) = x+tail (FullList _) = error "NList.tail is broken"++(++) :: FullList a -> FullList a -> FullList a+(++) x y = FullList ((Prelude.++) (fromFL x) (fromFL y)) -- OK because both already full++sortNub :: (Eq a, Ord a) => FullList a -> FullList a+sortNub xs =+ case (sort . nub . fromFL $ xs) of+ [] -> error "sortNub is broken"+ (y:ys) -> y !: ys++-- Mapping over a non-empty list gives a non-empty list+instance Functor FullList where+ fmap f (FullList x) = FullList (map f x)++-- Adding something to a general list surely gives a non-empty list+infixr 5 !:++class Listable l where+ (!:) :: a -> l a -> FullList a++instance Listable [] where+ (!:) h t = FullList (h:t)++instance Listable FullList where+ (!:) h (FullList t) = FullList (h:t)++{-!+deriving instance NFData a => NFData (FullList a)+deriving instance Binary a => Binary (FullList a)+!-}+-- GENERATED START+++instance (NFData a) => NFData (FullList a) where+ rnf (FullList x1) = rnf x1 `seq` ()+++instance (Binary a) => Binary (FullList a) where+ put (FullList x1) = put x1+ get+ = do x1 <- get+ return (FullList x1)+-- GENERATED STOP
− src/MainGeni.lhs
@@ -1,126 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.--\chapter{Main}--Welcome to the GenI source code. The main module is where everything-starts from. If you're trying to figure out how GenI works, the main-action is in Geni and Tags -(chapters \ref{cha:Geni} and \ref{cha:Tags}). --\begin{code}-module Main (main) where-\end{code}--\ignore{-\begin{code}-import Control.Applicative ((<$>))-import Data.IORef(newIORef)-import Data.Typeable( Typeable )-import Data.Version ( showVersion )-import System.Environment(getArgs, getProgName)--import Paths_GenI ( version )--import NLP.GenI.Geni(emptyProgState)-import NLP.GenI.Console(consoleGeni)-import NLP.GenI.Configuration (treatArgs, optionsForStandardGenI, processInstructions,- usage, optionsSections, Params,- hasFlagP, BatchDirFlg(..), DisableGuiFlg(..),- DumpDerivationFlg(..), FromStdinFlg(..),- HelpFlg(..), VersionFlg(..), TestCaseFlg(..),- RegressionTestModeFlg(..), RunUnitTestFlg(..),- )-import NLP.GenI.Regression (regressionGeni)-import NLP.GenI.Test (runTests)--#ifdef DISABLE_GUI-import NLP.GenI.Configuration(setFlagP)-import NLP.GenI.Geni(ProgStateRef)-#else-import NLP.GenI.Gui(guiGeni)-#endif--#ifdef DISABLE_GUI-guiGeni :: ProgStateRef -> IO ()-guiGeni = consoleGeni-#endif-\end{code}-}--In figure \ref{fig:code-outline-main} we show what happens from main: First, we-hand control off to either the console or the graphical user interface. These-functions then do all the business stuff like loading files and figuring out-what to generate. From there, they invoke the the generation step-\fnref{runGeni} which does surface realisation from A-Z. Alternately, the-graphical interface could invoke a graphical debugger which also does surface-realisation from A-Z but allows you to intervene, inspect and stop at each-step.--\begin{figure}-\begin{center}-\includegraphics[scale=0.25]{images/code-outline-main}-\label{fig:code-outline-main}-\caption{How the GenI entry point is used}-\end{center}-\end{figure}--\begin{code}-main :: IO ()-main = do - pname <- getProgName- args <- getArgs- confArgs <- forceGuiFlag <$> (processInstructions =<< treatArgs optionsForStandardGenI args)- let pst = emptyProgState confArgs- pstRef <- newIORef pst- let has :: (Typeable f, Typeable x) => (x -> f) -> Bool- has = flip hasFlagP confArgs- mustRunInConsole = has DumpDerivationFlg || has FromStdinFlg || has BatchDirFlg- canRunInConsole = has TestCaseFlg- case () of- _ | has HelpFlg -> putStrLn (usage optionsSections pname)- | has VersionFlg -> putStrLn ("GenI " ++ showVersion version)- | has RunUnitTestFlg -> runTests- | has RegressionTestModeFlg -> regressionGeni pstRef- | mustRunInConsole -> consoleGeni pstRef- | not (has DisableGuiFlg) -> guiGeni pstRef- | canRunInConsole -> consoleGeni pstRef- | otherwise -> fail $ unlines- [ "GenI must either be run..."- , " - with the graphical interface enabled"- , " - in regression testing mode"- , " - in self-diagnostic unit test mode"- , " - with a test case specified"- , " - with a batch directory specified or"- , " - with --dump"- , " - with --from-stdin"- ]--forceGuiFlag :: Params -> Params-#ifdef DISABLE_GUI-forceGuiFlag = setFlagP DisableGuiFlg ()-#else-forceGuiFlag = id-#endif-\end{code}--% TODO-% Define what is and what is not exported from the modules. -% In particular in BTypes take care to export the inspection function -% but not the types.-% Re-write functions in Main as needed.-% Change input in Lexicon and Grammar to allow more than one anchor.
+ src/NLP/GenI.hs view
@@ -0,0 +1,872 @@+-- GenI surface realiser+-- Copyright (C) 2005 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++{-# LANGUAGE ScopedTypeVariables, ExistentialQuantification, TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}++-- | This is the interface between the front and backends of the generator. The GUI+-- and the console interface both talk to this module, and in turn, this module+-- talks to the input file parsers and the surface realisation engine.+module NLP.GenI (+ -- * Main interface++ -- ** Program state and configuration+ ProgState(..), ProgStateRef, emptyProgState,+ LexicalSelector,++ -- ** Running GenI+ runGeni,+ GeniResults(..),+ GeniResult(..), isSuccess, GeniError(..), GeniSuccess(..),+ GeniLexSel(..),+ ResultType(..),++ -- * Helpers+ initGeni, extractResults,+ lemmaSentenceString, prettyResult,+ showRealisations, histogram,+ getTraces,++ -- ** Loading things+ loadEverything,+ Loadable(..),+ loadLexicon,+ loadGeniMacros,+ loadTestSuite, parseSemInput,+ loadRanking, BadInputException(..),+ loadFromString,+ )+where+++import Control.Applicative ((<$>),(<*>))+import Control.DeepSeq+import Control.Exception+import Control.Monad.Error+import Data.Binary (Binary, decodeFile)+import Data.IORef (IORef, readIORef, modifyIORef)+import Data.List+import Data.Maybe (fromMaybe)+import Data.Monoid ( mappend, mempty )+import Data.Text ( Text )+import Data.Typeable (Typeable)+import System.CPUTime( getCPUTime )+import System.IO ( stderr )+import qualified Data.Map as Map+import qualified Data.Text as T+import qualified Data.Text.IO as T++import Data.FullList ( fromFL )+import Text.JSON+import qualified System.IO.UTF8 as UTF8++import NLP.GenI.Configuration+ ( Params, customMorph, customSelector+ , getFlagP, hasFlagP, hasOpt, Optimisation(NoConstraints)+ , MacrosFlg(..), LexiconFlg(..), TestSuiteFlg(..)+ , MorphInfoFlg(..), MorphCmdFlg(..)+ , RankingConstraintsFlg(..)+ , PartialFlg(..)+ , FromStdinFlg(..), VerboseModeFlg(..)+ , NoLoadTestSuiteFlg(..)+ , RootFeatureFlg(..)+ , TracesFlg(..)+ , grammarType+ , GrammarType(..)+ )+import NLP.GenI.General+ ( histogram, geniBug, snd3, first3, ePutStr, ePutStrLn, eFlush,+ -- mkLogname,+ )+import NLP.GenI.GeniVal+import NLP.GenI.LexicalSelection ( LexicalSelector, LexicalSelection(..), defaultLexicalSelector )+import NLP.GenI.Lexicon+import NLP.GenI.Morphology+import NLP.GenI.OptimalityTheory+import NLP.GenI.Parser (geniMacros, geniTagElems,+ geniLexicon, geniTestSuite,+ geniTestSuiteString, geniSemanticInput,+ geniMorphInfo,+ runParser,+ ParseError,+ )+import NLP.GenI.Pretty+import NLP.GenI.Semantics+import NLP.GenI.Statistics+import NLP.GenI.Tag ( TagElem, idname, tsemantics, ttrace, setTidnums )+import NLP.GenI.TestSuite ( TestCase(..) )+import NLP.GenI.TreeSchema+import NLP.GenI.Warning+import qualified NLP.GenI.Builder as B++-- -- DEBUG+-- import Control.Monad.Writer+-- import NLP.GenI.Lexicon+-- import NLP.GenI.LexicalSelection+-- import NLP.GenI.FeatureStructures++-- --------------------------------------------------------------------+-- ProgState+-- --------------------------------------------------------------------++-- | The program state consists of its configuration options and abstract,+-- cleaned up representations of all the data it's had to load into memory+-- (tree schemata files, lexicon files, etc). The intention is for the+-- state to stay static until the next time something triggers some file+-- loading.+data ProgState = ProgState+ { pa :: Params -- ^ the current configuration+ , gr :: Macros -- ^ tree schemata+ , le :: Lexicon -- ^ lexical entries+ , morphinf :: MorphInputFn -- ^ function to extract morphological+ -- information from the semantics (you may+ -- instead be looking for+ -- 'NLP.GenI.Configuration.customMorph')+ , ranking :: OtRanking -- ^ OT constraints (optional)+ , traces :: [Text] -- ^ simplified traces (optional)+ }++type ProgStateRef = IORef ProgState++-- | The program state when you start GenI for the very first time+emptyProgState :: Params -> ProgState+emptyProgState args = ProgState+ { pa = args+ , gr = []+ , le = []+ , morphinf = const Nothing+ , traces = []+ , ranking = []+ }++-- --------------------------------------------------------------------+-- Interface+-- Loading and parsing+-- --------------------------------------------------------------------++-- | We have one master function that loads all the files GenI is expected to+-- use. This just calls the sub-loaders below, some of which are exported+-- for use by the graphical interface. The master function also makes sure+-- to complain intelligently if some of the required files are missing.+loadEverything :: ProgStateRef -> IO() +loadEverything pstRef =+ do pst <- readIORef pstRef+ --+ let config = pa pst+ isMissing f = not $ hasFlagP f config+ -- grammar type+ isNotPreanchored = grammarType config /= PreAnchored+ isNotPrecompiled = grammarType config /= PreCompiled+ useTestSuite = isMissing FromStdinFlg+ && isMissing NoLoadTestSuiteFlg+ -- display + let errormsg =+ concat $ intersperse ", " [ msg | (con, msg) <- errorlst, con ]+ errorlst =+ [ (isMissing RootFeatureFlg,+ "a root feature [empty feature is fine if you are not using polarity filtering]")+ , (isNotPrecompiled && isMissing MacrosFlg,+ "a tree file")+ , (isNotPreanchored && isMissing LexiconFlg,+ "a lexicon file")+ , (useTestSuite && isMissing TestSuiteFlg,+ "a test suite") ]+ unless (null errormsg) $ fail ("Please specify: " ++ errormsg)+ -- we only have to read in grammars from the simple format+ case grammarType config of + PreAnchored -> return ()+ PreCompiled -> return ()+ _ -> loadGeniMacros pstRef >> return ()+ -- we don't have to read in the lexicon if it's already pre-anchored+ when isNotPreanchored $ loadLexicon pstRef >> return ()+ -- in any case, we have to...+ loadMorphInfo pstRef+ when useTestSuite $ loadTestSuite pstRef >> return ()+ -- the trace filter file+ loadTraces pstRef+ -- OT ranking+ loadRanking pstRef+++-- | The file loading functions all work the same way: we load the file,+-- and try to parse it. If this doesn't work, we just fail in IO, and+-- GenI dies. If we succeed, we update the program state passed in as+-- an IORef.+class Loadable x where+ lParse :: FilePath -- ^ source (optional)+ -> String -> Either ParseError x+ lSet :: x -> ProgState -> ProgState+ lSummarise :: x -> String++-- | Note that here we assume the input consists of UTF-8 encoded file+lParseFromFile :: Loadable x => FilePath -> IO (Either ParseError x)+lParseFromFile f = lParse f `fmap` UTF8.readFile f++-- | Returns the input too (convenient for type checking)+lSetState :: Loadable x => ProgStateRef -> x -> IO x+lSetState pstRef x = modifyIORef pstRef (lSet x) >> return x++-- to be phased out+throwOnParseError :: String -> Either ParseError x -> IO x+throwOnParseError descr (Left err) = throwIO (BadInputException descr err)+throwOnParseError _ (Right p) = return p++data BadInputException = BadInputException String ParseError+ deriving (Show, Typeable)++instance Exception BadInputException++data L a = Loadable a => L++-- | Load something, exiting GenI if we have not been given the+-- appropriate flag+loadOrDie :: forall f a . (Eq f, Typeable f, Loadable a)+ => L a+ -> (FilePath -> f) -- ^ flag+ -> String+ -> ProgStateRef+ -> IO a+loadOrDie L flg descr pstRef =+ withFlagOrDie flg pstRef descr $ \f -> do+ v <- verbosity pstRef+ x <- withLoadStatus v f descr lParseFromFile+ >>= throwOnParseError descr+ >>= lSetState pstRef+ return x++-- | Load something from a string rather than a file+loadFromString :: Loadable a => ProgStateRef+ -> String -- ^ description+ -> String -- ^ string to load+ -> IO a+loadFromString pstRef descr s =+ throwOnParseError descr (lParse "" s) >>= lSetState pstRef++instance Loadable Lexicon where+ lParse f = fmap toLexicon . runParser geniLexicon () f+ where+ fixEntry = finaliseVars "" -- anonymise singletons for performance+ . sorter+ toLexicon = map fixEntry+ sorter l = l { isemantics = (sortByAmbiguity . isemantics) l }+ lSet x p = p { le = x }+ lSummarise x = show (length x) ++ " lemmas"++instance Loadable Macros where+ lParse f = runParser geniMacros () f+ lSet x p = p { gr = x }+ lSummarise x = show (length x) ++ " schemata"++loadLexicon :: ProgStateRef -> IO Lexicon+loadLexicon = loadOrDie (L :: L Lexicon) LexiconFlg "lexicon"++-- | The macros are stored as a hashing function in the monad.+loadGeniMacros :: ProgStateRef -> IO Macros+loadGeniMacros pstRef =+ withFlagOrDie MacrosFlg pstRef descr $ \f -> do+ v <- verbosity pstRef+ withLoadStatus v f descr (parseFromFileMaybeBinary lParseFromFile)+ >>= throwOnParseError "tree schemata"+ >>= lSetState pstRef+ where+ descr = "trees"++-- | Load something, but only if we are configured to do so+loadOptional :: forall f a . (Eq f, Typeable f, Loadable a)+ => L a+ -> (FilePath -> f) -- ^ flag+ -> String+ -> ProgStateRef+ -> IO ()+loadOptional L flg descr pstRef =+ withFlagOrIgnore flg pstRef $ \f -> do+ v <- verbosity pstRef+ x <- withLoadStatus v f descr lParseFromFile+ >>= throwOnParseError descr+ >>= lSetState pstRef+ let _ = x :: a+ return () -- ignore++newtype MorphFnL = MorphFnL MorphInputFn++instance Loadable MorphFnL where+ lParse f = fmap (MorphFnL . readMorph) . runParser geniMorphInfo () f+ lSet (MorphFnL x) p = p { morphinf = x }+ lSummarise _ = "morphinfo"++newtype TracesL = TracesL [Text]++instance Loadable TracesL where+ lParse _ = Right . TracesL . T.lines . T.pack+ lSet (TracesL xs) p = p { traces = xs }+ lSummarise (TracesL xs) = show (length xs) ++ " traces"++instance Loadable OtRanking where+ lParse _ = resultToEither2 . decode+ lSet r p = p { ranking = r }+ lSummarise _ = "ranking"++loadMorphInfo :: ProgStateRef -> IO ()+loadMorphInfo = loadOptional (L :: L MorphFnL) MorphInfoFlg "morphological info"++loadTraces :: ProgStateRef -> IO ()+loadTraces = loadOptional (L :: L TracesL) TracesFlg "traces"++loadRanking :: ProgStateRef -> IO ()+loadRanking = loadOptional (L :: L OtRanking) RankingConstraintsFlg "OT constraints"++resultToEither2 :: Result a -> Either ParseError a+resultToEither2 r =+ case resultToEither r of+ Left e -> runParser (fail e) () "" [] -- convoluted way to generate a Parsec error+ Right x -> Right x++-- Target semantics+--+-- Reading in the target semantics (or test suite) is a little more+-- complicated. It follows the same general schema as above, except+-- that we parse the file twice: once for our internal representation,+-- and once to get a string representation of each test case. The+-- string representation is for the graphical interface; it avoids us+-- figuring out how to pretty-print things because we can assume the+-- user will format it the way s/he wants.++newtype TestSuiteL = TestSuiteL [TestCase]++instance Loadable TestSuiteL where+ lParse f s =+ case runParser geniTestSuite () f s of+ Left e -> Left e+ Right sem -> case runParser geniTestSuiteString () f s of+ Left e -> Left e+ Right mStrs -> Right (TestSuiteL (zipWith cleanup sem mStrs))+ where+ cleanup tc str =+ tc { tcSem = first3 sortSem (tcSem tc)+ , tcSemString = str }+ --+ lSet (TestSuiteL _) p = p+ lSummarise (TestSuiteL x) = show (length x) ++ " cases"++-- |+loadTestSuite :: ProgStateRef -> IO [TestCase]+loadTestSuite pstRef = do+ TestSuiteL xs <- loadOrDie (L :: L TestSuiteL) TestSuiteFlg "test suite" pstRef+ return xs++parseSemInput :: String -> Either ParseError SemInput+parseSemInput = fmap smooth . runParser geniSemanticInput () "semantics"+ where+ smooth (s,r,l) = (sortSem s, sort r, l)++-- Helpers for loading files++withFlag :: forall f a . (Eq f, Typeable f)+ => (FilePath -> f) -- ^ flag+ -> ProgStateRef+ -> IO a -- ^ null action+ -> (FilePath -> IO a) -- ^ job+ -> IO a+withFlag flag pstRef z job =+ do config <- pa `fmap` readIORef pstRef+ case getFlagP flag config of+ Nothing -> z+ Just x -> job x++withFlagOrIgnore :: forall f . (Eq f, Typeable f)+ => (FilePath -> f) -- ^ flag+ -> ProgStateRef+ -> (FilePath -> IO ())+ -> IO ()+withFlagOrIgnore flag pstRef = withFlag flag pstRef (return ())++withFlagOrDie :: forall f a . (Eq f, Typeable f)+ => (FilePath -> f) -- ^ flag+ -> ProgStateRef+ -> String+ -> (FilePath -> IO a)+ -> IO a+withFlagOrDie flag pstRef description =+ withFlag flag pstRef (fail msg)+ where+ msg = "Please specify a " ++ description ++ " file!"++withLoadStatus :: Loadable a+ => Bool -- ^ verbose+ -> FilePath -- ^ file to load+ -> String -- ^ description+ -> (FilePath -> IO (Either ParseError a)) -- ^ parsing cmd+ -> IO (Either ParseError a)+withLoadStatus False f _ p = p f+withLoadStatus True f d p = do+ ePutStr $ unwords [ "Loading", d, f ++ "... " ]+ eFlush+ mx <- p f+ ePutStrLn $ either (const "ERROR") (\x -> lSummarise x ++ " loaded") mx+ return mx++parseFromFileMaybeBinary :: Binary a+ => (FilePath -> IO (Either ParseError a))+ -> FilePath+ -> IO (Either ParseError a)+parseFromFileMaybeBinary p f =+ if (".genib" `isSuffixOf` f)+ then Right `fmap` decodeFile f+ else p f++-- --------------------------------------------------------------------+-- Surface realisation - entry point+-- --------------------------------------------------------------------++-- | 'GeniResults' is the outcome of running GenI on a single input semantics.+-- Each distinct result is returned as a single 'GeniResult' (NB: a single+-- result may expand into multiple strings through morphological+-- post-processing),+data GeniResults = GeniResults+ { grResults :: [GeniResult] -- ^ one per chart item+ , grGlobalWarnings :: [Text] -- ^ usually from lexical selection+ , grStatistics :: Statistics -- ^ things like number of chart items+ -- to help study efficiency+ }++data GeniResult = GError GeniError+ | GSuccess GeniSuccess+ deriving (Ord, Eq)++isSuccess :: GeniResult -> Bool+isSuccess (GSuccess _) = True+isSuccess (GError _) = False++data GeniError = GeniError [Text]+ deriving (Ord, Eq)++data GeniSuccess = GeniSuccess+ { grLemmaSentence :: LemmaPlusSentence -- ^ “original” uninflected result + , grRealisations :: [Text] -- ^ results after morphology+ , grResultType :: ResultType+ , grWarnings :: [Text] -- ^ warnings “local” to this particular+ -- item, cf. 'grGlobalWarnings'+ , grDerivation :: B.TagDerivation -- ^ derivation tree behind the result+ , grOrigin :: Integer -- ^ normally a chart item id+ , grLexSelection :: [GeniLexSel] -- ^ the lexical selection behind+ -- this result (info only)+ , grRanking :: Int -- ^ see 'NLP.GenI.OptimalityTheory'+ , grViolations :: [OtViolation] -- ^ which OT constraints were violated+ } deriving (Ord, Eq)++data GeniLexSel = GeniLexSel+ { nlTree :: Text+ , nlTrace :: [Text]+ } deriving (Ord, Eq)++data ResultType = CompleteResult | PartialResult deriving (Ord, Eq)++instance Pretty GeniError where+ pretty (GeniError xs) = T.intercalate "\n" $ map ("Error:" <+>) xs++-- | Entry point! (the most useful function to know here)+-- +-- * Initialises the realiser (lexical selection, among other things),+--+-- * Runs the builder (the surface realisation engine proper)+--+-- * Unpacks the builder results +--+-- * Finalises the results (morphological generation)+--+-- In addition to the results, this returns a generator state. The latter is+-- is mostly useful for debugging via the graphical interface.+-- Note that we assumes that you have already loaded in your grammar and+-- parsed your input semantics.+runGeni :: ProgStateRef -> SemInput -> B.Builder st it Params -> IO (GeniResults,st)+runGeni pstRef semInput builder = do+ pst <- readIORef pstRef+ let config = pa pst+ run = B.run builder+ -- step 1: lexical selection+ (initStuff, initWarns) <- initGeni pstRef semInput+ --force evaluation before measuring start time to avoid including grammar/lexicon parsing.+ start <- rnf initStuff `seq` getCPUTime+ -- step 2: chart generation+ let (finalSt, stats) = run initStuff config+ -- step 3: unpacking and+ -- step 4: post-processing+ results <- extractResults pstRef builder finalSt+ --force evaluation before measuring end time to account for all the work that should be done.+ end <- rnf results `seq` getCPUTime+ let elapsedTime = picosToMillis $! end - start+ diff = round (elapsedTime :: Double) :: Int+ stats2 = updateMetrics (incrIntMetric "gen_time" (fromIntegral diff) ) stats+ gresults = GeniResults { grResults = results+ , grStatistics = stats2+ , grGlobalWarnings = map showWarnings (fromGeniWarnings initWarns)+ }+ return (gresults, finalSt)+ where+ showWarnings = T.intercalate "\n" . showGeniWarning++-- | This is a helper to 'runGenI'. It's mainly useful if you are building+-- interactive GenI debugging tools.+--+-- Given a builder state,+--+-- * Unpacks the builder results+--+-- * Finalises the results (morphological generation)+extractResults :: ProgStateRef -> B.Builder st it Params -> st -> IO [GeniResult]+extractResults pstRef builder finalSt = do+ config <- pa <$> readIORef pstRef+ -- step 3: unpacking+ let uninflected = B.unpack builder finalSt+ (rawResults, resultTy) =+ if null uninflected && hasFlagP PartialFlg config+ then (B.partial builder finalSt, PartialResult)+ else (uninflected , CompleteResult)+ status = B.finished builder finalSt+ -- step 4: post-processing+ finaliseResults pstRef (resultTy, status, rawResults)++-- --------------------------------------------------------------------+-- Surface realisation - sub steps+-- --------------------------------------------------------------------++-- | 'initGeni' performs lexical selection and strips the input semantics of+-- any morpohological literals+initGeni :: ProgStateRef -> SemInput -> IO (B.Input, GeniWarnings)+initGeni pstRef semInput_ = do+ pst <- readIORef pstRef+ let semInput = stripMorphStuff pst+ . maybeRemoveConstraints pst+ $ semInput_+ -- lexical selection+ selection <- runLexSelection pstRef semInput+ -- strip morphological predicates+ let initStuff = B.Input + { B.inSemInput = semInput+ , B.inLex = lsLexEntries selection+ , B.inCands = map (\c -> (c,-1)) (lsAnchored selection)+ }+ return (initStuff, lsWarnings selection)+ where+ stripMorphStuff pst = first3 (stripMorphSem (morphinf pst))+ -- disable constraints if the NoConstraintsFlg pessimisation is active+ maybeRemoveConstraints pst =+ if hasOpt NoConstraints (pa pst) then removeConstraints else id++-- | 'finaliseResults' does any post-processing steps that we want to integrate+-- into mainline GenI. So far, this consists of morphological realisation and+-- OT ranking+finaliseResults :: ProgStateRef -> (ResultType, B.GenStatus, [B.Output]) -> IO [GeniResult]+finaliseResults pstRef (ty, status, os) = do+ pst <- readIORef pstRef+ -- morph TODO: make this a bit safer+ mss <- case getFlagP MorphCmdFlg (pa pst) of+ Nothing -> let morph = fromMaybe (map sansMorph) (customMorph (pa pst))+ in return (morph sentences)+ Just cmd -> map snd `fmap` inflectSentencesUsingCmd cmd sentences+ -- OT ranking+ let unranked = zipWith (sansRanking pst) os mss+ rank = rankResults (getTraces pst) grDerivation (ranking pst)+ successes = map addRanking (rank unranked)+ failures = case status of+ B.Error str -> [GeniError [str]]+ B.Finished -> []+ B.Active -> []+ return (map GError failures ++ map GSuccess successes)+ where+ sentences = map snd3 os+ sansRanking pst (i,l,d) rs = GeniSuccess+ { grLemmaSentence = l+ , grRealisations = moRealisations rs+ , grWarnings = moWarnings rs+ , grDerivation = d+ , grLexSelection = map (\x -> GeniLexSel x (getTraces pst x)) (B.lexicalSelection d)+ , grRanking = -1+ , grViolations = []+ , grResultType = ty+ , grOrigin = i+ }+ addRanking (i,res,vs) = res { grViolations = vs, grRanking = i }++-- --------------------------------------------------------------------+-- Displaying results+-- --------------------------------------------------------------------++-- | Show the sentences produced by the generator, in a relatively compact form+showRealisations :: [String] -> String+showRealisations [] = "(none)"+showRealisations xs = unlines . map sho . Map.toList . histogram $ xs+ where+ sho (x,1) = x+ sho (x,c) = x ++ " (" ++ show c ++ " instances)"++-- | No morphology! Pretend the lemma string is a sentence+lemmaSentenceString :: GeniSuccess -> Text+lemmaSentenceString = T.unwords . map lpLemma . grLemmaSentence++prettyResult :: ProgState -> GeniSuccess -> Text+prettyResult pst nr =+ T.intercalate "\n" . map showOne . grRealisations $ nr+ where+ showOne str = pretty theRanking <> ". " <> str <> "\n" <> violations+ violations = prettyViolations tracesFn verbose (grViolations nr)+ theRanking = grRanking nr+ verbose = hasFlagP VerboseModeFlg (pa pst)+ tracesFn = getTraces pst++-- | 'getTraces' is most likely useful for grammars produced by a+-- metagrammar system. Given a tree name, we retrieve the ``trace''+-- information from the grammar for all trees that have this name. We+-- assume the tree name was constructed by GenI; see the source code for+-- details.+getTraces :: ProgState -> Text -> [Text]+getTraces pst tname =+ filt $ concat [ ptrace t | t <- gr pst, pidname t == readPidname tname ]+ where+ filt = case traces pst of+ [] -> id+ theTs -> filter (`elem` theTs)++-- | We assume the name was constructed by 'combineName'+readPidname :: Text -> Text+readPidname n =+ case T.splitOn ":" n of+ (_:_:p:_) -> p+ _ -> geniBug "NLP.GenI.readPidname or combineName are broken"++-- --------------------------------------------------------------------+-- Lexical selection+-- --------------------------------------------------------------------++-- | Runs the lexical selection (be it the standard GenI version or+-- a custom function supplied by a user) and runs the results+-- through the universal 'finaliseLexSelection'.+--+-- Also hunts for some warning conditions+runLexSelection :: ProgStateRef -> SemInput -> IO LexicalSelection+runLexSelection pstRef (tsem,_,litConstrs) = do+ pst <- readIORef pstRef+ let config = pa pst+ verbose = hasFlagP VerboseModeFlg config+ -- perform lexical selection+ selector <- getLexicalSelector pstRef+ selection <- selector (gr pst) (le pst) tsem+ let lexCand = lsLexEntries selection+ candFinal = finaliseLexSelection (morphinf pst) tsem litConstrs (lsAnchored selection)+ -- status+ when verbose $ T.hPutStrLn stderr . T.unlines $+ "Lexical items selected:"+ : map (indent . showLexeme . fromFL . iword) lexCand+ ++ ["Trees anchored (family) :"]+ ++ map (indent . idname) candFinal+ -- warnings+ let semWarnings = case missingLiterals candFinal tsem of+ [] -> []+ xs -> [NoLexSelection xs]+ return $ selection { lsAnchored = candFinal+ , lsWarnings = mkGeniWarnings semWarnings `mappend` lsWarnings selection+ }+ where+ indent x = ' ' `T.cons` x++-- | Grab the lexical selector from the config, or return the standard GenI+-- version if none is supplied+getLexicalSelector :: ProgStateRef -> IO LexicalSelector+getLexicalSelector pstRef = do+ config <- pa <$> readIORef pstRef+ case (customSelector config, grammarType config) of+ (Just s, _) -> return s+ (Nothing, PreAnchored) -> mkPreAnchoredLexicalSelector pstRef+ (Nothing, _) -> return defaultLexicalSelector++-- | @missingLiterals ts sem@ returns any literals in @sem@ that do not+-- appear in any of the @ts@ trees+missingLiterals :: [TagElem] -> [Literal GeniVal] -> [Literal GeniVal]+missingLiterals cands tsem =+ tsem \\ (nub $ concatMap tsemantics cands)++-- | Post-processes lexical selection results to things which+-- GenI considers applicable to all situations:+--+-- * attaches morphological information to trees+--+-- * throws out elementary trees that violate trace constraints+-- given by the user+--+-- * filters out any elementary tree whose semantics contains+-- things that are not in the input semantics+finaliseLexSelection :: MorphInputFn -> Sem -> [LitConstr] -> [TagElem] -> [TagElem]+finaliseLexSelection morph tsem litConstrs =+ setTidnums . considerCoherency . considerLc . considerMorph+ where+ -- attach any morphological information to the candidates+ considerMorph = attachMorph morph tsem+ -- filter out candidates which do not fulfill the trace constraints+ matchesLc t = all (`elem` myTrace) constrs+ where constrs = concat [ cs | (l,cs) <- litConstrs, l `elem` mySem ]+ mySem = tsemantics t+ myTrace = ttrace t+ considerLc = filter matchesLc+ -- filter out candidates whose semantics has bonus stuff which does+ -- not occur in the input semantics+ considerCoherency = filter (all (`elem` tsem) . tsemantics)++-- --------------------------------------------------------------------+-- Pre-selection and pre-anchoring+-- --------------------------------------------------------------------++newtype PreAnchoredL = PreAnchoredL [TagElem]++instance Loadable PreAnchoredL where+ lParse f = fmap PreAnchoredL+ . runParser geniTagElems () f+ lSet _ p = p -- this does not update prog state at all+ lSummarise (PreAnchoredL xs) = show (length xs) ++ " trees"++readPreAnchored :: ProgStateRef -> IO [TagElem]+readPreAnchored pstRef = do+ PreAnchoredL xs <- loadOrDie (L :: L PreAnchoredL)+ MacrosFlg "preanchored trees" pstRef+ return xs++mkPreAnchoredLexicalSelector :: ProgStateRef -> IO LexicalSelector+mkPreAnchoredLexicalSelector pstRef = do+ xs <- readPreAnchored pstRef+ return (\_ _ _ -> return (LexicalSelection xs [] mempty))++-- --------------------------------------------------------------------+-- Boring utility code+-- --------------------------------------------------------------------++verbosity :: ProgStateRef -> IO Bool+verbosity = fmap (hasFlagP VerboseModeFlg . pa)+ . readIORef++instance JSON GeniResult where+ readJSON j =+ case readJSON j of+ Ok s -> Ok (GSuccess s)+ Error _ -> GError `fmap` readJSON j+ showJSON (GSuccess x) = showJSON x+ showJSON (GError x) = showJSON x++instance JSON GeniSuccess where+ readJSON j = do+ jo <- fromJSObject `fmap` readJSON j+ let field x = maybe (fail $ "Could not find: " ++ x) readJSON+ $ lookup x jo+ GeniSuccess <$> field "raw"+ <*> field "realisations"+ <*> field "result-type"+ <*> field "warnings"+ <*> field "derivation"+ <*> field "chart-item"+ <*> field "lexical-selection"+ <*> field "ranking"+ <*> field "violations"+ showJSON nr =+ JSObject . toJSObject $ [ ("raw", showJSON $ grLemmaSentence nr)+ , ("realisations", showJSONs $ grRealisations nr)+ , ("derivation", showJSONs $ grDerivation nr)+ , ("lexical-selection", showJSONs $ grLexSelection nr)+ , ("ranking", showJSON $ grRanking nr)+ , ("violations", showJSONs $ grViolations nr)+ , ("result-type", showJSON $ grResultType nr)+ , ("chart-item", showJSON $ grOrigin nr)+ , ("warnings", showJSONs $ grWarnings nr)+ ]++instance JSON GeniError where+ readJSON j =+ do jo <- fromJSObject `fmap` readJSON j+ let field x = maybe (fail $ "Could not find: " ++ x) readJSON+ $ lookup x jo+ GeniError <$> field "errors"+ showJSON (GeniError xs) =+ JSObject . toJSObject $ [ ("errors", showJSON xs) ]++instance JSON ResultType where+ readJSON j =+ do js <- fromJSString `fmap` readJSON j+ case js of+ "partial" -> return PartialResult+ "complete" -> return CompleteResult+ ty -> fail $ "unknown result type: " ++ ty+ showJSON CompleteResult = JSString $ toJSString "complete"+ showJSON PartialResult = JSString $ toJSString "partial"++instance JSON GeniLexSel where+ readJSON j =+ do jo <- fromJSObject `fmap` readJSON j+ let field x = maybe (fail $ "Could not find: " ++ x) readJSON+ $ lookup x jo+ GeniLexSel <$> field "lex-item"+ <*> field "trace"+ showJSON x =+ JSObject . toJSObject $ [ ("lex-item", showJSON $ nlTree x)+ , ("trace", showJSONs $ nlTrace x)+ ]++-- Converts picoseconds to milliseconds.+picosToMillis :: Integer -> Double+picosToMillis t = realToFrac t / (10^(9 :: Int))++{-+data MNAME = MNAME deriving Typeable+logname :: String+logname = mkLogname MNAME+-}++{-!+deriving instance NFData GeniResult+deriving instance NFData GeniSuccess+deriving instance NFData GeniError+deriving instance NFData ResultType+deriving instance NFData GeniLexSel+!-}++-- GENERATED START++ +instance NFData GeniResult where+ rnf (GError x1) = rnf x1 `seq` ()+ rnf (GSuccess x1) = rnf x1 `seq` ()++ +instance NFData GeniSuccess where+ rnf (GeniSuccess x1 x2 x3 x4 x5 x6 x7 x8 x9)+ = rnf x1 `seq`+ rnf x2 `seq`+ rnf x3 `seq`+ rnf x4 `seq`+ rnf x5 `seq` rnf x6 `seq` rnf x7 `seq` rnf x8 `seq` rnf x9 `seq` ()++ +instance NFData GeniError where+ rnf (GeniError x1) = rnf x1 `seq` ()++ +instance NFData ResultType where+ rnf CompleteResult = ()+ rnf PartialResult = ()++ +instance NFData GeniLexSel where+ rnf (GeniLexSel x1 x2) = rnf x1 `seq` rnf x2 `seq` ()+-- GENERATED STOP
− src/NLP/GenI/Btypes.lhs
@@ -1,757 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.--\chapter{Btypes}-\label{cha:Btypes}--This module provides basic datatypes like GNode, as well as operations-on trees, nodes and semantics. Things here are meant to be relatively-low-level and primitive (well, with the exception of feature structure-unification, that is).--\ignore{-\begin{code}-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-# LANGUAGE MultiParamTypeClasses, TypeSynonymInstances, FlexibleInstances, DeriveDataTypeable #-}-module NLP.GenI.Btypes(- -- Datatypes- GNode(..), GType(Subs, Foot, Lex, Other), NodeName,- Ttree(..), MTtree, SemPols, TestCase(..),- Ptype(Initial,Auxiliar,Unspecified),- Pred, Flist, AvPair(..), GeniVal(..),- Lexicon, ILexEntry(..), MorphLexEntry, Macros, Sem, LitConstr, SemInput, Subst,- emptyLE, emptyGNode, emptyMacro,-- -- GNode stuff- gCategory, showLexeme, lexemeAttributes, gnnameIs,-- -- Functions from Tree GNode- plugTree, spliceTree,- root, rootUpd, foot, setLexeme, setAnchor,-- -- Functions from Sem- toKeys, subsumeSem, sortSem, showSem, showPred,- emptyPred,-- -- Functions from Flist- sortFlist, unify, unifyFeat, mergeSubst,- showFlist, showPairs, showAv,-- -- Other functions- replace, DescendGeniVal(..), replaceList,- Collectable(..), Idable(..),- alphaConvert, alphaConvertById,- fromGConst, fromGVar,- isConst, isVar, isAnon,-- -- Polarities--) where----- import Debug.Trace -- for test stuff-import Data.List-import Data.Maybe ( mapMaybe )-import Data.Function ( on )-import Data.Generics (Data)-import Data.Typeable (Typeable)-import qualified Data.Map as Map-import qualified Data.Set as Set-import Data.Tree--import Data.Generics.PlateDirect--import NLP.GenI.General(filterTree, listRepNode, snd3, geniBug)-import NLP.GenI.GeniVal----instance Show (IO()) where--- show _ = ""-\end{code}-}--% -----------------------------------------------------------------------\section{Grammar}-% ------------------------------------------------------------------------A grammar is composed of some unanchored trees (macros) and individual-lexical entries. The trees are grouped into families. Every lexical-entry is associated with a single family. See section section-\ref{sec:combine_macros} for the process that combines lexical items-and trees into a set of anchored trees.--\begin{code}-type MTtree = Ttree GNode-type Macros = [MTtree]--data Ttree a = TT- { params :: [GeniVal]- , pfamily :: String- , pidname :: String- , pinterface :: Flist- , ptype :: Ptype- , psemantics :: Maybe Sem- , ptrace :: [String]- , tree :: Tree a }- deriving (Show, Data, Typeable)--data Ptype = Initial | Auxiliar | Unspecified- deriving (Show, Eq, Data, Typeable)--instance Biplate (Ttree String) GeniVal where- biplate (TT zps x1 x2 zint x3 zsem x4 x5) =- plate TT ||* zps |- x1 |- x2- ||+ zint |- x3- |+ zsem |- x4 |- x5--instance Biplate (Ttree GNode) GeniVal where- biplate (TT zps x1 x2 zint x3 zsem x4 zt) =- plate TT ||* zps |- x1 |- x2- ||+ zint |- x3- |+ zsem |- x4- |+ zt--instance DescendGeniVal (Ttree GNode) where- descendGeniVal s mt =- mt { params = descendGeniVal s (params mt)- , tree = descendGeniVal s (tree mt)- , pinterface = descendGeniVal s (pinterface mt)- , psemantics = descendGeniVal s (psemantics mt) }--instance (Collectable a) => Collectable (Ttree a) where- collect mt = (collect $ params mt) . (collect $ tree mt) .- (collect $ psemantics mt) . (collect $ pinterface mt)---- | A null tree which you can use for various debugging or display purposes.-emptyMacro :: MTtree-emptyMacro = TT { params = [],- pidname = "",- pfamily = "",- pinterface = [],- ptype = Unspecified,- psemantics = Nothing,- ptrace = [],- tree = Node emptyGNode []- }-\end{code}--\paragraph{Lexical entries}--\begin{code}--- | A lexicon maps semantic predicates to lexical entries.-type Lexicon = Map.Map String [ILexEntry]-type SemPols = [Int]-data ILexEntry = ILE- { -- normally just a singleton, useful for merging synonyms- iword :: [String]- , ifamname :: String- , iparams :: [GeniVal]- , iinterface :: Flist- , ifilters :: Flist- , iequations :: Flist- , iptype :: Ptype- , isemantics :: Sem- , isempols :: [SemPols] }- deriving (Show, Eq, Data, Typeable)--instance Biplate ILexEntry GeniVal where- biplate (ILE x1 x2 zps zint zfilts zeq x3 zsem x4) =- plate ILE |- x1 |- x2- ||* zps- ||+ zint- ||+ zfilts- ||+ zeq |- x3- ||+ zsem |- x4--instance DescendGeniVal ILexEntry where- descendGeniVal s i =- i { iinterface = descendGeniVal s (iinterface i)- , iequations = descendGeniVal s (iequations i)- , isemantics = descendGeniVal s (isemantics i)- , iparams = descendGeniVal s (iparams i) }--instance Collectable ILexEntry where- collect l = (collect $ iinterface l) . (collect $ iparams l) .- (collect $ ifilters l) . (collect $ iequations l) .- (collect $ isemantics l)--emptyLE :: ILexEntry-emptyLE = ILE { iword = [],- ifamname = "",- iparams = [],- iinterface = [],- ifilters = [],- iptype = Unspecified,- isemantics = [],- iequations = [],- isempols = [] }-\end{code}--\begin{code}-type MorphLexEntry = (String,String,Flist)-\end{code}--% -----------------------------------------------------------------------\section{TAG nodes (GNode)}-% ------------------------------------------------------------------------\begin{code}--- | A single node of a TAG tree.-data GNode = GN{gnname :: NodeName,- gup :: Flist, -- ^ top feature structure- gdown :: Flist, -- ^ bottom feature structure- ganchor :: Bool, -- ^ @False@ for na nodes- glexeme :: [String], -- ^ @[]@ for na nodes- gtype :: GType,- gaconstr :: Bool,- gorigin :: String -- ^ for TAG, this would be the elementary tree- -- that this node originally came from- }- deriving (Eq, Data, Typeable)--instance Biplate GNode GeniVal where- biplate (GN x1 zu zd x2 x3 x4 x5 x6) =- plate GN |- x1- ||+ zu- ||+ zd |- x2 |- x3 |- x4 |- x5 |- x6--instance Biplate (Tree GNode) GeniVal where- biplate (Node zn zkids) = plate Node |+ zn ||+ zkids---- Node type used during parsing of the grammar-data GType = Subs | Foot | Lex | Other- deriving (Show, Eq, Data, Typeable)--type NodeName = String---- | A null 'GNode' which you can use for various debugging or display purposes.-emptyGNode :: GNode-emptyGNode = GN { gnname = "",- gup = [], gdown = [],- ganchor = False,- glexeme = [],- gtype = Other,- gaconstr = False,- gorigin = "" }--gnnameIs :: NodeName -> GNode -> Bool-gnnameIs n = (== n) . gnname-\end{code}--A TAG node may have a category. In the core GenI algorithm, there is nothing-which distinguishes the category from any other attributes. But for some-other uses, such as checking if it is a result or for display purposes, we-do treat this attribute differently. We take here the convention that the-category of a node is associated to the attribute ``cat''.-\begin{code}--- | Return the value of the "cat" attribute, if available-gCategory :: Flist -> Maybe GeniVal-gCategory top =- case [ v | AvPair "cat" v <- top ] of- [] -> Nothing- [c] -> Just c- _ -> geniBug $ "Impossible case: node with more than one category"-\end{code}--A TAG node might also have a lexeme. If we are lucky, this is explicitly-set in the glexeme field of the node. Otherwise, we try to guess it from-a list of distinguished attributes (in order of preference).-\begin{code}--- | Attributes recognised as lexemes, in order of preference-lexemeAttributes :: [String]-lexemeAttributes = [ "lex", "phon", "cat" ]-\end{code}--\paragraph{show (GNode)} the default show for GNode tries to-be very compact; it only shows the value for cat attribute-and any flags which are marked on that node.--\begin{code}-instance Show GNode where- show gn =- let cat_ = case gCategory.gup $ gn of- Nothing -> []- Just c -> show c- lex_ = showLexeme $ glexeme gn- --- stub = concat $ intersperse ":" $ filter (not.null) [ cat_, lex_ ]- extra = case (gtype gn) of- Subs -> " !"- Foot -> " *"- _ -> if (gaconstr gn) then " #" else ""- in stub ++ extra---- FIXME: will have to think of nicer way - one which involves--- unpacking the trees :-(-showLexeme :: [String] -> String-showLexeme [] = ""-showLexeme [l] = l-showLexeme xs = concat $ intersperse "|" xs-\end{code}--A Replacement on a GNode consists of replacements on its top and bottom-feature structures--\begin{code}-instance DescendGeniVal GNode where- descendGeniVal s gn =- gn { gup = descendGeniVal s (gup gn)- , gdown = descendGeniVal s (gdown gn) }-\end{code}--% -----------------------------------------------------------------------\section{Tree manipulation}-% ------------------------------------------------------------------------\begin{code}-root :: Tree a -> a-root (Node a _) = a--rootUpd :: Tree a -> a -> Tree a-rootUpd (Node _ l) b = (Node b l)--foot :: Tree GNode -> GNode-foot t = case filterTree (\n -> gtype n == Foot) t of- [x] -> x- _ -> geniBug $ "foot returned weird result"-\end{code}--\begin{code}--- | Given a lexical item @s@ and a Tree GNode t, returns the tree t'--- where l has been assigned to the anchor node in t'-setAnchor :: [String] -> Tree GNode -> Tree GNode-setAnchor s t =- let filt (Node a []) = (gtype a == Lex && ganchor a)- filt _ = False- in case listRepNode (setLexeme s) filt [t] of- ([r],True) -> r- _ -> geniBug $ "setLexeme " ++ show s ++ " returned weird result"---- | Given a lexical item @l@ and a tree node @n@ (actually a subtree--- with no children), return the same node with the lexical item as--- its unique child. The idea is that it converts terminal lexeme nodes--- into preterminal nodes where the actual terminal is the given lexical--- item-setLexeme :: [String] -> Tree GNode -> Tree GNode-setLexeme l (Node a []) = Node a [ Node subanc [] ]- where subanc = emptyGNode { gnname = '_' : ((gnname a) ++ ('.' : (concat l)))- , gaconstr = True- , glexeme = l}-setLexeme _ _ = geniBug "impossible case in setLexeme - subtree with kids"-\end{code}--\subsection{Substitution and Adjunction}--This module handles just the tree-cutting aspects of TAG substitution and-adjunction. We do substitution with a very general \fnreflite{plugTree}-function, whose only job is to plug two trees together at a specified node.-Note that this function is also used to implement adjunction.--\begin{code}--- | Plug the first tree into the second tree at the specified node.--- Anything below the second node is silently discarded.--- We assume the trees are pluggable; it is treated as a bug if--- they are not!-plugTree :: Tree NodeName -> NodeName -> Tree NodeName -> Tree NodeName-plugTree male n female =- case listRepNode (const male) (nmatch n) [female] of- ([r], True) -> r- _ -> geniBug $ "unexpected plug failure at node " ++ n---- | Given two trees 'auxt' and 't', splice the tree 'auxt' into--- 't' via the TAG adjunction rule.-spliceTree :: NodeName -- ^ foot node of the aux tree- -> Tree NodeName -- ^ aux tree- -> NodeName -- ^ place to adjoin in target tree- -> Tree NodeName -- ^ target tree- -> Tree NodeName-spliceTree f auxT n targetT =- case findSubTree n targetT of -- excise the subtree at n- Nothing -> geniBug $ "Unexpected adjunction failure. " ++- "Could not find node " ++ n ++ " of target tree."- Just eT -> -- plug the excised bit into the aux- let auxPlus = plugTree eT f auxT- -- plug the augmented aux at n- in plugTree auxPlus n targetT--nmatch :: NodeName -> Tree NodeName -> Bool-nmatch n (Node a _) = a == n--findSubTree :: NodeName -> Tree NodeName -> Maybe (Tree NodeName)-findSubTree n n2@(Node x ks)- | x == n = Just n2- | otherwise = case mapMaybe (findSubTree n) ks of- [] -> Nothing- (h:_) -> Just h-\end{code}--% -----------------------------------------------------------------------\section{Features and variables}-% ------------------------------------------------------------------------\begin{code}-type Flist = [AvPair]-data AvPair = AvPair { avAtt :: String- , avVal :: GeniVal }- deriving (Ord, Eq, Data, Typeable)--instance Biplate AvPair GeniVal where- biplate (AvPair a v) = plate AvPair |- a |* v-\end{code}--\subsection{Collectable}--A Collectable is something which can return its variables as a set.-By variables, what I most had in mind was the GVar values in a-GeniVal. This notion is probably not very useful outside the context of-alpha-conversion task, but it seems general enough that I'll keep it-around for a good bit, until either some use for it creeps up, or I find-a more general notion that I can transform this into.--\begin{code}-class Collectable a where- collect :: a -> Set.Set String -> Set.Set String--instance Collectable a => Collectable (Maybe a) where- collect Nothing s = s- collect (Just x) s = collect x s--instance (Collectable a => Collectable [a]) where- collect l s = foldr collect s l--instance (Collectable a => Collectable (Tree a)) where- collect = collect.flatten---- Pred is what I had in mind here-instance ((Collectable a, Collectable b, Collectable c)- => Collectable (a,b,c)) where- collect (a,b,c) = collect a . collect b . collect c--instance Collectable GeniVal where- collect (GVar v) s = Set.insert v s- collect _ s = s--instance Collectable AvPair where- collect (AvPair _ b) = collect b--instance Collectable GNode where- collect n = (collect $ gdown n) . (collect $ gup n)-\end{code}--\subsection{DescendGeniVal}-\label{sec:replacable}-\label{sec:replacements}--The idea of replacing one variable value with another is something that-appears all over the place in GenI. So we try to smooth out its use by-making a type class out of it.--\begin{code}--\end{code}--Substitution on list consists of performing substitution on-each item. Each item, is independent of the other,-of course.--\begin{code}-instance DescendGeniVal a => DescendGeniVal (Map.Map k a) where- descendGeniVal s = {-# SCC "descendGeniVal" #-} Map.map (descendGeniVal s)--instance DescendGeniVal AvPair where- descendGeniVal s (AvPair a v) = {-# SCC "descendGeniVal" #-} AvPair a (descendGeniVal s v)--instance DescendGeniVal a => DescendGeniVal (String, a) where- descendGeniVal s (n,v) = {-# SCC "descendGeniVal" #-} (n,descendGeniVal s v)--instance DescendGeniVal ([String], Flist) where- descendGeniVal s (a,v) = {-# SCC "descendGeniVal" #-} (a, descendGeniVal s v)-\end{code}--\subsection{Idable}--\begin{code}--- | An Idable is something that can be mapped to a unique id.--- You might consider using this to implement Ord, but I won't.--- Note that the only use I have for this so far (20 dec 2005)--- is in alpha-conversion.-class Idable a where- idOf :: a -> Integer-\end{code}--\subsection{Other feature and variable stuff}--Our approach to $\alpha$-conversion works by appending a unique suffix-to all variables in an object. See section \ref{sec:fs_unification} for-why we want this.--\begin{code}-alphaConvertById :: (Collectable a, DescendGeniVal a, Idable a) => a -> a-alphaConvertById x = {-# SCC "alphaConvertById" #-}- alphaConvert ('-' : (show . idOf $ x)) x--alphaConvert :: (Collectable a, DescendGeniVal a) => String -> a -> a-alphaConvert suffix x = {-# SCC "alphaConvert" #-}- let vars = Set.elems $ collect x Set.empty- convert v = GVar (v ++ suffix)- subst = Map.fromList $ map (\v -> (v, convert v)) vars- in replace subst x-\end{code}--\begin{code}--- | Sort an Flist according with its attributes-sortFlist :: Flist -> Flist-sortFlist = sortBy (compare `on` avAtt)--showFlist :: Flist -> String-showFlist f = "[" ++ showPairs f ++ "]"--showPairs :: Flist -> String-showPairs = unwords . map showAv--showAv :: AvPair -> String-showAv (AvPair y z) = y ++ ":" ++ show z--instance Show AvPair where- show = showAv-\end{code}--% -----------------------------------------------------------------------\section{Semantics}-\label{btypes_semantics}-% ------------------------------------------------------------------------\begin{code}--- handle, predicate, parameters-type Pred = (GeniVal, GeniVal, [GeniVal])-type Sem = [Pred]-type LitConstr = (Pred, [String])-type SemInput = (Sem,Flist,[LitConstr])--instance Biplate Pred GeniVal where- biplate (g1, g2, g3) = plate (,,) |* g1 |* g2 ||* g3--instance Biplate (Maybe Sem) GeniVal where- biplate (Just s) = plate Just ||+ s- biplate Nothing = plate Nothing--data TestCase = TestCase- { tcName :: String- , tcSemString :: String -- ^ for gui- , tcSem :: SemInput- , tcExpected :: [String] -- ^ expected results (for testing)- , tcOutputs :: [(String, Map.Map (String,String) [String])]- -- ^ results we actually got, and their traces (for testing)- } deriving Show--emptyPred :: Pred-emptyPred = (GAnon,GAnon,[])-\end{code}--A replacement on a predicate is just a replacement on its parameters--\begin{code}-instance DescendGeniVal Pred where- descendGeniVal s (h, n, lp) = (descendGeniVal s h, descendGeniVal s n, descendGeniVal s lp)-\end{code}--\begin{code}-showSem :: Sem -> String-showSem l =- "[" ++ (unwords $ map showPred l) ++ "]"--showPred :: Pred -> String-showPred (h, p, l) = showh ++ show p ++ "(" ++ unwords (map show l) ++ ")"- where- hideh (GConst [x]) = "genihandle" `isPrefixOf` x- hideh _ = False- --- showh = if (hideh h) then "" else (show h) ++ ":"-\end{code}--\begin{code}--- | Given a Semantics, return the string with the proper keys--- (propsymbol+arity) to access the agenda-toKeys :: Sem -> [String]-toKeys l = map (\(_,prop,par) -> show prop ++ (show $ length par)) l-\end{code}--\subsection{Semantic subsumption}-\label{fn:subsumeSem}--FIXME: comment fix--Given tsem the input semantics, and lsem the semantics of a potential-lexical candidate, returns a list of possible ways that the lexical-semantics could subsume the input semantics. We return a pair with-the semantics that would result from unification\footnote{We need to-do this because there may be anonymous variables}, and the-substitutions that need to be propagated throughout the rest of the-lexical item later on.--Note: we return more than one possible substitution because s could be-different subsets of ts. Consider, for example, \semexpr{love(j,m),- name(j,john), name(m,mary)} and the candidate \semexpr{name(X,Y)}.--TODO WE ASSUME BOTH SEMANTICS ARE ORDERED and that the input semantics is-non-empty.--\begin{code}-subsumeSem :: Sem -> Sem -> [(Sem,Subst)]-subsumeSem tsem lsem =- subsumeSemHelper ([],Map.empty) (reverse tsem) (reverse lsem)-\end{code}--This is tricky because each substep returns multiple results. We solicit-the help of accumulators to keep things from getting confused.--\begin{code}-subsumeSemHelper :: (Sem,Subst) -> Sem -> Sem -> [(Sem,Subst)]-subsumeSemHelper _ [] _ =- error "input semantics is non-empty in subsumeSemHelper"-subsumeSemHelper acc _ [] = [acc]-subsumeSemHelper acc tsem (hd:tl) =- let (accSem,accSub) = acc- -- does the literal hd subsume the input semantics?- pRes = subsumePred tsem hd- -- toPred reconstructs the literal hd with new parameters p.- -- The head of the list is taken to be the handle.- toPred p = (head p, snd3 hd, tail p)- -- next adds a result from predication subsumption to- -- the accumulators and goes to the next recursive step- next (p,s) = subsumeSemHelper acc2 tsem2 tl2- where tl2 = replace s tl- tsem2 = replace s tsem- acc2 = (toPred p : accSem, mergeSubst accSub s)- in concatMap next pRes-\end{code}--\fnlabel{subsumePred}-The first Sem s1 and second Sem s2 are the same when we start we circle on s2-looking for a match for Pred, and meanwhile we apply the partical substitutions-to s1. Note: we treat the handle as if it were a parameter.--\begin{code}-subsumePred :: Sem -> Pred -> [([GeniVal],Subst)]-subsumePred [] _ = []-subsumePred ((h1, p1, la1):l) (pred2@(h2,p2,la2)) =- -- if we found the proper predicate- if ((p1 == p2) && (length la1 == length la2))- then let mrs = unify (h1:la1) (h2:la2)- next = subsumePred l pred2- in maybe next (:next) mrs- else if (p1 < p2) -- note that the semantics have to be reversed!- then []- else subsumePred l pred2-\end{code}--\subsection{Other semantic stuff}--\begin{code}--- | Sort semantics first according to its predicate, and then to its handles.-sortSem :: Sem -> Sem-sortSem = sortBy (\(h1,p1,a1) (h2,p2,a2) -> compare (p1, h1:a1) (p2, h2:a2))-\end{code}--% ---------------------------------------------------------------------\subsection{Feature structure unification}-\label{sec:fs_unification}-% ----------------------------------------------------------------------Feature structure unification takes two feature lists as input. If it-fails, it returns Nothing. Otherwise, it returns a tuple with:--\begin{enumerate}-\item a unified feature structure list-\item a list of variable replacements that will need to be propagated- across other feature structures with the same variables-\end{enumerate}--Unification fails if, at any point during the unification process, the-two lists have different constant values for the same attribute.-For example, unification fails on the following inputs because they have-different values for the \textit{number} attribute:--\begin{quotation}-\fs{\it cat:np\\ \it number:3\\}-\fs{\it cat:np\\ \it number:2\\}-\end{quotation}--Note that the following input should also fail as a result on the-coreference on \textit{?X}.--\begin{quotation}-\fs{\it cat:np\\ \it one: 1\\ \it two:2\\}-\fs{\it cat:np\\ \it one: ?X\\ \it two:?X\\}-\end{quotation}--On the other hand, any other pair of feature lists should unify-succesfully, even those that do not share the same attributes.-Below are some examples of successful unifications:--\begin{quotation}-\fs{\it cat:np\\ \it one: 1\\ \it two:2\\}-\fs{\it cat:np\\ \it one: ?X\\ \it two:?Y\\}-$\rightarrow$-\fs{\it cat:np\\ \it one: 1\\ \it two:2\\},-\end{quotation}--\begin{quotation}-\fs{\it cat:np\\ \it number:3\\}-\fs{\it cat:np\\ \it case:nom\\}-$\rightarrow$-\fs{\it cat:np\\ \it case:nom\\ \it number:3\\},-\end{quotation}--\begin{code}--- | 'unifyFeat' performs feature structure unification, under the--- these assumptions about the input:------ * Features are ordered------ * The Flists do not share variables (renaming has already--- been done.------ The features are allowed to have different sets of attributes,--- beacuse we use 'alignFeat' to realign them.-unifyFeat :: Monad m => Flist -> Flist -> m (Flist, Subst)-unifyFeat f1 f2 =- {-# SCC "unification" #-}- let (att, val1, val2) = unzip3 $ alignFeat f1 f2- in att `seq`- do (res, subst) <- unify val1 val2- return (zipWith AvPair att res, subst)---- | 'alignFeat' is a pre-procesing step used to ensure that feature structures--- have the same set of keys. If a key is missing in one, we copy it to the--- other with an anonymous value.------ The two feature structures must be sorted for this to work-alignFeat :: Flist -> Flist -> [(String,GeniVal,GeniVal)]-alignFeat f1 f2 = alignFeatH f1 f2 []--alignFeatH :: Flist -> Flist -> [(String,GeniVal,GeniVal)] -> [(String,GeniVal,GeniVal)]-alignFeatH [] [] acc = reverse acc-alignFeatH [] (AvPair f v :x) acc = alignFeatH [] x ((f,GAnon,v) : acc)-alignFeatH x [] acc = alignFeatH [] x acc-alignFeatH fs1@(AvPair f1 v1:l1) fs2@(AvPair f2 v2:l2) acc =- case compare f1 f2 of- EQ -> alignFeatH l1 l2 ((f1, v1, v2) : acc)- LT -> alignFeatH l1 fs2 ((f1, v1, GAnon) : acc)- GT -> alignFeatH fs1 l2 ((f2, GAnon, v2) : acc)-\end{code}--
− src/NLP/GenI/BtypesBinary.hs
@@ -1,59 +0,0 @@-{-# OPTIONS -fno-warn-orphans #-}-module NLP.GenI.BtypesBinary where--import Data.Binary-import NLP.GenI.Btypes---- auto-generated by the Data.Binary BinaryDerive tool-instance Binary NLP.GenI.Btypes.Ptype where- put Initial = putWord8 0- put Auxiliar = putWord8 1- put Unspecified = putWord8 2- get = do- tag_ <- getWord8- case tag_ of- 0 -> return Initial- 1 -> return Auxiliar- 2 -> return Unspecified- _ -> fail "no parse"-instance Binary NLP.GenI.Btypes.GeniVal where- put (GConst a) = putWord8 0 >> put a- put (GVar a) = putWord8 1 >> put a- put GAnon = putWord8 2- get = do- tag_ <- getWord8- case tag_ of- 0 -> get >>= \a -> return (GConst a)- 1 -> get >>= \a -> return (GVar a)- 2 -> return GAnon- _ -> fail "no parse"-instance Binary NLP.GenI.Btypes.GNode where- put (GN a b c d e f g h) = put a >> put b >> put c >> put d >> put e >> put f >> put g >> put h- get = get >>= \a -> get >>= \b -> get >>= \c -> get >>= \d -> get >>= \e -> get >>= \f -> get >>= \g -> get >>= \h -> return (GN a b c d e f g h)--instance Binary NLP.GenI.Btypes.GType where- put Subs = putWord8 0- put Foot = putWord8 1- put Lex = putWord8 2- put Other = putWord8 3- get = do- tag_ <- getWord8- case tag_ of- 0 -> return Subs- 1 -> return Foot- 2 -> return Lex- 3 -> return Other- _ -> fail "no parse"-instance (Binary a) => Binary (NLP.GenI.Btypes.Ttree a) where- put (TT a b c d e f g h) = put a >> put b >> put c >> put d >> put e >> put f >> put g >> put h- get = get >>= \a -> get >>= \b -> get >>= \c -> get >>= \d -> get >>= \e -> get >>= \f -> get >>= \g -> get >>= \h -> return (TT a b c d e f g h)---instance Binary NLP.GenI.Btypes.AvPair where- put (AvPair a b) = put a >> put b- get = get >>= \a -> get >>= \b -> return (AvPair a b)--instance Binary NLP.GenI.Btypes.ILexEntry where- put (ILE a b c d e f g h i) = put a >> put b >> put c >> put d >> put e >> put f >> put g >> put h >> put i- get = get >>= \a -> get >>= \b -> get >>= \c -> get >>= \d -> get >>= \e -> get >>= \f -> get >>= \g -> get >>= \h -> get >>= \i -> return (ILE a b c d e f g h i)-
+ src/NLP/GenI/Builder.hs view
@@ -0,0 +1,404 @@+-- GenI surface realiser+-- Copyright (C) 2005 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE DeriveDataTypeable #-}++{-|+The heavy lifting of GenI, the whole chart/agenda mechanism, can be+implemented in many ways. To make it easier to write different+algorithms for GenI and compare them, we provide a single interface+for what we call Builders.++This interface is then used called by the Geni module and by the+graphical interface. Note that each builder has its own graphical+interface and that we do a similar thing in the graphical interface+code to make it possible to use these GUIs.+-}++module NLP.GenI.Builder (+ TagDerivation, Builder(..), GenStatus(..),+ lexicalSelection, FilterStatus(..),incrCounter, num_iterations,+ (>-->),+ num_comparisons, chart_size,+ SemBitMap, defineSemanticBits, semToBitVector, bitVectorToSem, DispatchFilter, condFilter,+ defaultStepAll,+ BuilderState, UninflectedDisjunction(..), Input(..), unlessEmptySem,+ initStats, Output, SentenceAut, run, queryCounter, defaultMetricNames, preInit+)+where++import Control.Monad.State.Strict+import Data.Bits ( (.&.), (.|.), bit )+import Data.List ( delete, sort, nub )+import Data.Maybe ( mapMaybe, fromMaybe, maybeToList )+import Data.Tree ( flatten )+import Prelude hiding ( init )+import Data.Text ( Text )+import qualified Data.Map as Map+import qualified Data.Text as T++import Control.DeepSeq++import Data.Generics ( Data )+import Data.Typeable ( Typeable )++import NLP.GenI.Automaton (NFA, automatonPaths, automatonPathSets, numStates, numTransitions)+import NLP.GenI.Configuration+ ( getListFlagP, getFlagP, modifyFlagP, Params,+ DetectPolaritiesFlg(..),+ MetricsFlg(..),+ RootFeatureFlg(..),+ Optimisation(..), hasOpt,+ )+import NLP.GenI.FeatureStructure ( Flist, sortFlist, mkFeatStruct )+import NLP.GenI.General ( BitVector, snd3, thd3, geniBug )+import NLP.GenI.GeniVal ( GeniVal, DescendGeniVal(..), Collectable(collect), finaliseVarsById )+import NLP.GenI.Lexicon ( LexEntry )+import NLP.GenI.Morphology.Types+import NLP.GenI.Polarity (PolResult(..), buildAutomaton, detectPolPaths)+import NLP.GenI.Pretty+import NLP.GenI.Semantics ( SemInput, Sem, Literal )+import NLP.GenI.Statistics (Statistics, incrIntMetric,+ Metric(IntMetric), updateMetrics,+ queryMetrics, queryIntMetric,+ addMetric, emptyStats,+ )+import NLP.GenI.Tag+ ( TagElem(idname,tsemantics,ttree), setTidnums+ , TagDerivation, dsChild, dsParent+ )+import NLP.GenI.TreeSchema ( GNode(..), GType(Subs, Foot) )++data GenStatus = Finished+ | Active+ | Error Text++data Builder st it pa = Builder+ { init :: Input -> pa -> (st, Statistics)+ -- ^ initialise the machine from the semantics and lexical selection + , step :: BuilderState st () -- ^ run a realisation step+ , stepAll :: BuilderState st () -- ^ run all realisations steps until completion+ --+ , finished :: st -> GenStatus -- ^ determine if realisation is finished+ , unpack :: st -> [Output] -- ^ unpack chart results into a list of sentences+ , partial :: st -> [Output]+ }++type Output = (Integer, LemmaPlusSentence, TagDerivation)++-- | To simplify interaction with the backend, we provide a single data+-- structure which represents all the inputs a backend could take.++data Input = + Input { inSemInput :: SemInput+ , inLex :: [LexEntry] -- ^ for the debugger+ , inCands :: [(TagElem, BitVector)] -- ^ tag tree+ }++-- Uninflected words and sentences++-- | A SentenceAut represents a set of sentences in the form of an automaton.+-- The labels of the automaton are the words of the sentence. But note! +-- “word“ in the sentence is in fact a tuple (lemma, inflectional feature+-- structures). Normally, the states are defined as integers, with the+-- only requirement being that each one, naturally enough, is unique.+type SentenceAut = NFA Int LemmaPlus++data UninflectedDisjunction = UninflectedDisjunction [Text] (Flist GeniVal) deriving (Data, Typeable)++instance DescendGeniVal UninflectedDisjunction where+ descendGeniVal s (UninflectedDisjunction a v) = {-# SCC "descendGeniVal" #-} UninflectedDisjunction a (descendGeniVal s v)++instance Collectable UninflectedDisjunction where+ collect (UninflectedDisjunction _ b) = collect b++-- BuilderState++-- To cleanly seperate the tracking of statistics from the core functionality of a+-- builder, we use a State transformer to thread a Statistics state monad inside of+-- our main monad.+type BuilderState s a = StateT s (State Statistics) a++-- ----------------------------------------------------------------------+-- Helper functions for Builders+-- ----------------------------------------------------------------------++-- Initialisation+--+-- There's a few things that need to be run before even initialising the builder.+-- One of these is running some of the optimisations (namely the polarity stuff),+-- which is made complicated by the fact that they are optional. Another of these+-- to assign each of the trees with a unique ID. Note that this has to be done+-- after the polarity optimisation because this optimisation may introduce new+-- items into the lexical selection. Finally, we must also make sure we perform+-- alpha conversion so that unification does not do the wrong thing when two trees+-- have the same variables.++preInit :: Input -> Params -> (Input, PolResult)+preInit input config =+ let (cand,_) = unzip $ inCands input+ seminput = inSemInput input+ --+ extraPol = Map.empty+ polsToDetect = fromMaybe (error "there should be a default for --detect-pols")+ $ getFlagP DetectPolaritiesFlg config+ rootFeat = mkFeatStruct $ getListFlagP RootFeatureFlg config+ -- do any optimisations+ isPol = hasOpt Polarised config+ -- polarity optimisation (if enabled)+ autstuff = buildAutomaton polsToDetect rootFeat extraPol seminput cand+ autpaths = map concat . automatonPathSets . prFinal $ autstuff+ combosPol = if isPol then autpaths else [considerHasSem cand]+ considerHasSem = filter (not . null . tsemantics)+ -- polarity automaton construction uses the zero literal semantic+ -- items, but it may be safer to filter them out now if we are not+ -- using it+ -- chart sharing optimisation+ (cands2, pathIds) = unzip $ detectPolPaths combosPol+ --+ fixate ts ps = zip (map finaliseVarsById $ setTidnums ts) ps+ input2 = input { inCands = fixate cands2 pathIds+ , inSemInput = (prSem autstuff, snd3 seminput, thd3 seminput) }+ -- note: autstuff is only useful for the graphical debugger+ in (input2, autstuff)++-- | Equivalent to 'id' unless the input contains an empty or uninstatiated+-- semantics+unlessEmptySem :: Input -> Params -> a -> a+unlessEmptySem input _+ | null semanticsErr = id+ | otherwise = error semanticsErr+ where+ (cands,_) = unzip $ inCands input+ nullSemCands = [ idname t | t <- cands, (null.tsemantics) t ]+ unInstSemCands = [ idname t | t <- cands, not $ Map.null $ collect (tsemantics t) Map.empty ]+ nullSemErr =+ "The following trees have a null semantics: " +++ T.unpack (T.unwords nullSemCands)+ unInstSemErr =+ "The following trees have an uninstantiated semantics: " +++ T.unpack (T.unwords unInstSemCands)+ semanticsErr =+ (if null nullSemCands then "" else nullSemErr ++ "\n") +++ (if null unInstSemCands then "" else unInstSemErr)++-- ----------------------------------------------------------------------+-- Running a surface realiser+-- ----------------------------------------------------------------------++-- | Performs surface realisation from an input semantics and a lexical selection.+--+-- Statistics tracked+--+-- * pol_used_bundles - number of bundled paths through the polarity automaton.+-- see 'NLP.GenI.Automaton.automatonPathSets'+--+-- * pol_used_paths - number of paths through the final automaton+--+-- * pol_seed_paths - number of paths through the seed automaton (i.e. with no polarities).+-- This is normally just 1, unless you have multi-literal semantics+--+-- * pol_total_states - combined number of states in the all the polarity automata+--+-- * pol_total_tras - combined number of transitions in all polarity automata+--+-- * pol_max_states - number of states in the polarity automaton with the most states+--+-- * pol_total_tras - number of transitions in the polarity automata with the most transitions+--+-- * sem_literals - number of literals in the input semantics+--+-- * lex_trees - total number of lexically selected trees++-- * lex_foot_nodes - total number of nodes of any sort in lexically selected trees+--+-- * lex_subst_nodes - total number of sustitution nodes in lexically selected trees+--+-- * lex_foot_nodes - total number of foot nodes in lexically selected trees+--+-- * plex_... - same as the lex_ equivalent, but after polarity filtering+run :: Builder st it Params -> Input -> Params -> (st, Statistics)+run builder input config_ =+ let -- 0 normalise the config+ config = modifyFlagP RootFeatureFlg sortFlist config_+ -- 1 run the setup stuff+ (input2, autstuff) = preInit input config+ auts = map snd3 (prIntermediate autstuff)+ -- 2 call the init stuff+ (iSt, iStats) = init builder input2 config+ -- 2b extra statistics+ autpaths = map concat . automatonPathSets . prFinal $ autstuff+ countsFor ts = (length ts, length nodes, length sn, length an)+ where nodes = concatMap (flatten.ttree) ts+ sn = [ n | n <- nodes, gtype n == Subs ]+ an = [ n | n <- nodes, gtype n == Foot ]+ (tsem,_,_) = inSemInput input+ cands = nub . map fst $ inCands input+ cands2 = nub . concatMap concat . automatonPathSets . prFinal $ autstuff+ countUp = do incrCounter "sem_literals" $ length tsem+ --+ incrCounter "lex_subst_nodes" snl+ incrCounter "lex_foot_nodes" anl+ incrCounter "lex_nodes" nl+ incrCounter "lex_trees" tl+ -- node count after polarities are taken into account+ incrCounter "plex_subst_nodes" snl2+ incrCounter "plex_foot_nodes" anl2+ incrCounter "plex_nodes" nl2+ incrCounter "plex_trees" tl2+ where (tl , nl , snl , anl ) = countsFor cands+ (tl2, nl2, snl2, anl2) = countsFor cands2+ -- 3 step through the whole thing+ stepAll_ = do countUp+ incrCounter "pol_used_bundles" $ length autpaths+ incrCounter "pol_used_paths" $ length . automatonPaths . prFinal $ autstuff+ incrCounter "pol_seed_paths" $ length . automatonPaths . prInitial $ autstuff+ incrCounter "pol_total_states" $ sum $ map numStates auts+ incrCounter "pol_total_trans" $ sum $ map numTransitions auts+ incrCounter "pol_max_states" $ maximum $ map numStates auts+ incrCounter "pol_max_trans" $ maximum $ map numTransitions auts+ stepAll builder+ in runState (execStateT stepAll_ iSt) iStats++-- ----------------------------------------------------------------------+-- Semantics and bit vectors+-- ----------------------------------------------------------------------++type SemBitMap = Map.Map (Literal GeniVal) BitVector++-- | assign a bit vector value to each literal in the semantics+-- the resulting map can then be used to construct a bit vector+-- representation of the semantics+defineSemanticBits :: Sem -> SemBitMap+defineSemanticBits sem = Map.fromList $ zip sem bits+ where+ bits = map bit [0..] -- 0001, 0010, 0100...++semToBitVector :: SemBitMap -> Sem -> BitVector+semToBitVector bmap sem = foldr (.|.) 0 $ map doLookup sem+ where doLookup p =+ case Map.lookup p bmap of+ Nothing -> geniBug $ "predicate " ++ prettyStr p ++ " not found in semanticBit map"+ Just b -> b++bitVectorToSem :: SemBitMap -> BitVector -> Sem+bitVectorToSem bmap vector =+ mapMaybe tryKey $ Map.toList bmap+ where tryKey (p,k) = if (k .&. vector == k) then Just p else Nothing++-- ----------------------------------------------------------------------+-- Generate step+-- ----------------------------------------------------------------------++-- | Default implementation for the 'stepAll' function in 'Builder'+defaultStepAll :: Builder st it pa -> BuilderState st ()+defaultStepAll b =+ do s <- get+ case finished b s of+ Active -> step b >> defaultStepAll b+ _ -> return ()++-- | Dispatching consists of assigning a chart item to the right part of the+-- chart (agenda, trash, results list, etc). This is implemented as a+-- series of filters which can either fail or succeed. If a filter fails,+-- it may modify the item before passing it on to future filters.+type DispatchFilter s a = a -> s (FilterStatus a)++data FilterStatus a = Filtered | NotFiltered a++-- | Sequence two dispatch filters.+(>-->) :: (Monad s) => DispatchFilter s a -> DispatchFilter s a -> DispatchFilter s a+f >--> f2 = \x -> f x >>= next+ where+ next y@Filtered = return y+ next (NotFiltered x2) = f2 x2++-- | If the item meets some condition, use the first filter, otherwise+-- use the second one.+condFilter :: (Monad s) => (a -> Bool)+ -> DispatchFilter s a -> DispatchFilter s a+ -> DispatchFilter s a+condFilter cond f1 f2 = \x -> if cond x then f1 x else f2 x++-- ----------------------------------------------------------------------+-- Statistics+-- ----------------------------------------------------------------------++modifyStats :: (Metric -> Metric) -> BuilderState st ()+modifyStats fn = lift $ modify $ updateMetrics fn++incrCounter :: String -> Int -> BuilderState st ()+incrCounter key n = modifyStats (incrIntMetric key n)++queryCounter :: String -> Statistics -> Maybe Int+queryCounter key s =+ case queryMetrics (queryIntMetric key) s of+ [] -> Nothing+ [c] -> Just c+ _ -> geniBug $ "More than one instance of the metric: " ++ key++-- Command line configuration++initStats :: Params -> Statistics+initStats pa =+ let mdefault ms = if "default" `elem` ms then defaultMetricNames else []+ identifyMs :: [String] -> [Metric]+ identifyMs ms = map namedMetric $ mdefault ms ++ delete "default" ms+ metrics = identifyMs $ fromMaybe [] $ getFlagP MetricsFlg pa+ in execState (mapM_ addMetric metrics) emptyStats++namedMetric :: String -> Metric+-- the default case is that it's an int metric+namedMetric n = IntMetric n 0++-- Note that the strings here are command-line strings, not metric names!+defaultMetricNames :: [ String ]+defaultMetricNames = [ num_iterations, chart_size, num_comparisons, gen_time ]++-- Common counters+--+-- These numbers allow us to keep track of how efficient our generator is+-- and where we are in the process (how many steps we've taken, etc)++num_iterations, chart_size, num_comparisons, gen_time :: String++num_iterations = "iterations"+chart_size = "chart_size"+num_comparisons = "comparisons"+gen_time = "gen_time"++-- ----------------------------------------------------------------------+-- strictly API-ish bits+-- ----------------------------------------------------------------------++-- | The names of lexically selected chart items used in a derivation+lexicalSelection :: TagDerivation -> [Text]+lexicalSelection = sort . nub+ . concatMap (\d -> dsChild d : maybeToList (dsParent d))++{-!+deriving instance NFData Input+!-}++-- GENERATED START++ +instance NFData Input where+ rnf (Input x1 x2 x3) = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` ()++-- GENERATED STOP
− src/NLP/GenI/Builder.lhs
@@ -1,562 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.--\chapter{Builder}-\label{cha:Builder}--The heavy lifting of GenI, the whole chart/agenda mechanism, can be-implemented in many ways. To make it easier to write different-algorithms for GenI and compare them, we provide a single interface-for what we call Builders.--This interface is then used called by the Geni module and by the-graphical interface. Note that each builder has its own graphical-interface and that we do a similar thing in the graphical interface-code to make it possible to use these GUIs. Maybe a little dose of-UML might help. See figure \ref{fig:builderUml}.--\begin{figure}-\begin{center}-\includegraphics[scale=0.5]{images/builderUml.pdf}-\label{fig:builderUml}-\caption{Essentially what the Builder interface provides}-\end{center}-\end{figure}--\ignore{-\begin{code}-module NLP.GenI.Builder-where--import Control.Applicative ( (<$>), (<*>) )-import Control.Monad.State.Strict-import Data.Bits ( (.&.), (.|.), bit, xor )-import Data.List ( (\\), maximum, delete, sort, nub )-import qualified Data.Map as Map-import Data.Maybe ( mapMaybe, fromMaybe )-import qualified Data.Set as Set-import Data.Tree ( flatten )-import Prelude hiding ( init )-import Text.JSON--import Data.Generics.PlateDirect-import Data.Generics ( Data )-import Data.Typeable ( Typeable )--import NLP.GenI.Automaton (NFA, automatonPaths, automatonPathSets, numStates, numTransitions)-import NLP.GenI.Configuration- ( getListFlagP, getFlagP, Params,- DetectPolaritiesFlg(..),- ExtraPolaritiesFlg(..), MetricsFlg(..),- RootFeatureFlg(..),- Optimisation(..), hasOpt,- )-import NLP.GenI.General (geniBug, BitVector, multiGroupByFM, fst3, snd3, thd3)-import NLP.GenI.Btypes- ( ILexEntry, SemInput, Sem, Pred, showPred, showSem,- AvPair(..), Flist, showFlist, gtype, GType(Subs, Foot),- DescendGeniVal(..), Collectable(collect), alphaConvertById,- GeniVal(GConst)- )-import NLP.GenI.GeniParsers ( geniFeats, runParser, CharParser )-import NLP.GenI.Polarity (PolResult, buildAutomaton, detectPolPaths)-import NLP.GenI.Statistics (Statistics, incrIntMetric,- Metric(IntMetric), updateMetrics,- queryMetrics, queryIntMetric,- addMetric, emptyStats,- )-import NLP.GenI.Tags ( TagElem(idname,tsemantics,ttree), setTidnums, TagDerivation, DerivationStep(..) )-\end{code}-}--\section{The interface}--All backends provide the same essential functionality:-\begin{description}-\item [run] calls init and stepAll and potentially wraps it with some- other functionality. -\item [init] initialise the machine from the semantics and lexical selection -\item [step] run a realisation step-\item [stepAll] run all realisations steps until completion-\item [finished] determine if realisation is finished-\item [stats] extract various statistics from it-\item [setStats] set the statistical information -\item [unpack] unpack chart results into a list of sentences-\end{description}--FIXME: need to update this comment--\begin{code}-data Builder st it pa = Builder- { init :: Input -> pa -> (st, Statistics)- --- , step :: BuilderState st ()- , stepAll :: BuilderState st ()- --- , finished :: st -> Bool- , unpack :: st -> [Output]- , partial :: st -> [Output] }--type Output = (LemmaPlusSentence, Derivation)-type Derivation = TagDerivation-\end{code}--To simplify interaction with the backend, we provide a single data-structure which represents all the inputs a backend could take.--\begin{code}-data Input = - Input { inSemInput :: SemInput- , inLex :: [ILexEntry] -- ^ for the debugger- , inCands :: [(TagElem, BitVector)] -- ^ tag tree- }-\end{code}--\section{Uninflected words and sentences}--Each word of an uninflected sentence consists of a lemma and some-feature structures.--\paragraph -A SentenceAut represents a set of sentences in the form of an automaton.-The labels of the automaton are the words of the sentence. But note! -``word'' in the sentence is in fact a tuple (lemma, inflectional feature-structures). Normally, the states are defined as integers, with the-only requirement being that each one, naturally enough, is unique.--\begin{code}-type SentenceAut = NFA Int LemmaPlus--data UninflectedDisjunction = UninflectedDisjunction [String] Flist deriving (Show, Data, Typeable)--instance Biplate UninflectedDisjunction GeniVal where- biplate (UninflectedDisjunction a v) = plate UninflectedDisjunction |- a ||+ v--instance DescendGeniVal UninflectedDisjunction where- descendGeniVal s (UninflectedDisjunction a v) = {-# SCC "descendGeniVal" #-} UninflectedDisjunction a (descendGeniVal s v)--instance Collectable UninflectedDisjunction where- collect (UninflectedDisjunction _ b) = collect b-\end{code}--\section{BuilderState}--To cleanly seperate the tracking of statistics from the core functionality of a-builder, we use a State transformer to thread a Statistics state monad inside of-our main monad.--\begin{code}-type BuilderState s a = StateT s (State Statistics) a-\end{code}--\section{Helper functions for Builders}--\subsection{Initialisation}-\label{fn:Builder:preInit}--There's a few things that need to be run before even initialising the builder.-One of these is running some of the optimisations (namely the polarity stuff),-which is made complicated by the fact that they are optional. Another of these-to assign each of the trees with a unique ID. Note that this has to be done-after the polarity optimisation because this optimisation may introduce new-items into the lexical selection. Finally, we must also make sure we perform-alpha conversion so that unification does not do the wrong thing when two trees-have the same variables.--\begin{code}-preInit :: Input -> Params -> (Input, (Int,Int,Int), PolResult)-preInit input config =- let (cand,_) = unzip $ inCands input- seminput = inSemInput input- --- extraPol = fromMaybe (Map.empty) $ getFlagP ExtraPolaritiesFlg config- polsToDetect = fromMaybe (error "there should be a default for --detect-pols")- $ getFlagP DetectPolaritiesFlg config- rootFeat = getListFlagP RootFeatureFlg config- -- do any optimisations- isPol = hasOpt Polarised config- -- polarity optimisation (if enabled)- autstuff = buildAutomaton polsToDetect rootFeat extraPol seminput cand- (_, seedAut, aut, sem2) = autstuff- autpaths = map concat $ automatonPathSets aut- combosPol = if isPol then autpaths else [cand]- -- chart sharing optimisation- (cands2, pathIds) = unzip $ detectPolPaths combosPol- -- the number of paths explored vs possible- polcount = (length autpaths, length $ automatonPaths aut, length $ automatonPaths seedAut)- --- fixate ts ps = zip (map alphaConvertById $ setTidnums ts) ps- input2 = input { inCands = fixate cands2 pathIds- , inSemInput = (sem2, snd3 seminput, thd3 seminput) }- -- note: autstuff is only useful for the graphical debugger- in (input2, polcount, autstuff)-\end{code}--\begin{code}--- | Equivalent to 'id' unless the input contains an empty or uninstatiated--- semantics-unlessEmptySem :: Input -> Params -> a -> a-unlessEmptySem input _ =- let (cands,_) = unzip $ inCands input- nullSemCands = [ idname t | t <- cands, (null.tsemantics) t ]- unInstSemCands = [ idname t | t <- cands, not $ Set.null $ collect (tsemantics t) Set.empty ]- nullSemErr = "The following trees have a null semantics: " ++ (unwords nullSemCands)- unInstSemErr = "The following trees have an uninstantiated semantics: " ++ (unwords unInstSemCands)- semanticsErr = (if null nullSemCands then "" else nullSemErr ++ "\n") ++- (if null unInstSemCands then "" else unInstSemErr)- in if null semanticsErr- then id- else error semanticsErr-\end{code}--\subsection{Running a surface realiser}--\begin{code}--- | Performs surface realisation from an input semantics and a lexical selection.------ Statistics tracked------ * pol_used_bundles - number of bundled paths through the polarity automaton.--- see 'NLP.GenI.Automaton.automatonPathSets'------ * pol_used_paths - number of paths through the final automaton------ * pol_seed_paths - number of paths through the seed automaton (i.e. with no polarities).--- This is normally just 1, unless you have multi-literal semantics------ * pol_total_states - combined number of states in the all the polarity automata------ * pol_total_tras - combined number of transitions in all polarity automata------ * pol_max_states - number of states in the polarity automaton with the most states------ * pol_total_tras - number of transitions in the polarity automata with the most transitions-run :: Builder st it Params -> Input -> Params -> (st, Statistics)-run builder input config =- let -- 1 run the setup stuff- (input2, polcount, autstuff) = preInit input config- auts = (\(x,_,_,_) -> map snd3 x) autstuff- -- 2 call the init stuff- (iSt, iStats) = init builder input2 config- -- 3 step through the whole thing- stepAll_ = do incrCounter "pol_used_bundles" $ fst3 polcount- incrCounter "pol_used_paths" $ snd3 polcount- incrCounter "pol_seed_paths" $ thd3 polcount- incrCounter "pol_total_states" $ sum $ map numStates auts- incrCounter "pol_total_trans" $ sum $ map numTransitions auts- incrCounter "pol_max_states" $ maximum $ map numStates auts- incrCounter "pol_max_trans" $ maximum $ map numTransitions auts- stepAll builder- in runState (execStateT stepAll_ iSt) iStats-\end{code}--\subsection{Semantics and bit vectors}--\begin{code}-type SemBitMap = Map.Map Pred BitVector---- | assign a bit vector value to each literal in the semantics--- the resulting map can then be used to construct a bit vector--- representation of the semantics-defineSemanticBits :: Sem -> SemBitMap-defineSemanticBits sem = Map.fromList $ zip sem bits- where- bits = map bit [0..] -- 0001, 0010, 0100...--semToBitVector :: SemBitMap -> Sem -> BitVector-semToBitVector bmap sem = foldr (.|.) 0 $ map doLookup sem- where doLookup p =- case Map.lookup p bmap of- Nothing -> geniBug $ "predicate " ++ showPred p ++ " not found in semanticBit map"- Just b -> b--bitVectorToSem :: SemBitMap -> BitVector -> Sem-bitVectorToSem bmap vector =- mapMaybe tryKey $ Map.toList bmap- where tryKey (p,k) = if (k .&. vector == k) then Just p else Nothing-\end{code}--\subsection{Index accesibility filtering}-\label{sec:iaf}--Index accesibility filtering was described in \cite{carroll05her}. This-is my attempt to adapt it to TAG. This filter works as a form of delayed-substitution, basically the exact opposite of delayed adjunction.--This might be wrong, but we say that an index is originally accesible if-it is the root node's idx attribute (no atomic disjunction; atomic-disjunction is as good as a variable as far I'm concerned)--FIXME: more about this later.-FIXME: are we sure we got the atomic disjunctions right?--\begin{code}-type IafMap = Map.Map String Sem---- | Return the literals of the semantics (in bit vector form)--- whose accesibility depends on the given index-dependentSem :: IafMap -> String -> Sem-dependentSem iafMap x = Map.findWithDefault [] x iafMap---- | Return the handle and arguments of a literal-literalArgs :: Pred -> [GeniVal]-literalArgs (h,_,args) = h:args--semToIafMap :: Sem -> IafMap-semToIafMap sem =- multiGroupByFM (concatMap fromUniConst . literalArgs) sem---- | Like 'fromGConst' but only for the non-disjoint ones: meant to be used as Maybe or List-fromUniConst :: (Monad m) => GeniVal -> m String-fromUniConst (GConst [x]) = return x-fromUniConst _ = fail "not a unique constant" -- we don't actually expect this failure msg to be used--getIdx :: Flist -> [GeniVal]-getIdx fs = [ v | AvPair "idx" v <- fs ]--ts_iafFailure :: [String] -> [Pred] -> String-ts_iafFailure is sem = "index accesibility failure -" ++ (unwords is) ++ "- blocked: " ++ showSem sem---- | Calculate the new set of accessibility/inaccesible indices, returning a--- a tuple of accesible / inaccesible indices-recalculateAccesibility :: (IafAble a) => a -> a-recalculateAccesibility i =- let oldAcc = iafAcc i- newAcc = iafNewAcc i- oldInacc = iafInacc i- newInacc = oldInacc ++ (oldAcc \\ newAcc)- in iafSetInacc newInacc $ iafSetAcc newAcc i---- | Return, in bitvector form, the portion of a semantics that is inaccesible--- from an item-iafBadSem :: (IafAble a) => IafMap -> SemBitMap- -> BitVector -- ^ the input semantics- -> (a -> BitVector) -- ^ the semantics of the item- -> a -> BitVector-iafBadSem iafMap bmap sem semfn i =- let -- the semantics we can't reach- inaccessible = foldr (.|.) 0 $ map (semToBitVector bmap . dependentSem iafMap) $ iafInacc i- -- the semantics we still _need_ to be able to reach- remaining = sem `xor` (semfn i)- -- where we're in trouble- in inaccessible .&. remaining--class IafAble a where- iafAcc :: a -> [String]- iafInacc :: a -> [String]- iafSetAcc :: [String] -> a -> a- iafSetInacc :: [String] -> a -> a- iafNewAcc :: a -> [String]-\end{code}--\subsection{Generate step}--\begin{code}--- | Default implementation for the 'stepAll' function in 'Builder'-defaultStepAll :: Builder st it pa -> BuilderState st ()-defaultStepAll b =- do s <- get- unless (finished b s) $- do step b- defaultStepAll b-\end{code}--\subsection{Dispatching new chart items}-\label{sec:dispatching}--Dispatching consists of assigning a chart item to the right part of the-chart (agenda, trash, results list, etc). This is implemented as a-series of filters which can either fail or succeed.--Counter-intuitively, success is defined as returning \verb!Nothing!.-Failure is defined as return \verb!Just!, because if a filter fails, it-has the right to modify the item for the next filter. For example, the-top and bottom unification filter succeeds if it \emph{cannot} unify-the top and bottom features of a node. It suceeds by putting the item-into the trash and returning Nothing. If it \emph{can} perform top and-bottom unification, we want to return the item where the top and bottom-nodes are unified. Failure is success, war is peace, freedom is-slavery, erase is backspace.--\begin{code}-type DispatchFilter s a = a -> s (Maybe a)---- | Sequence two dispatch filters.-(>-->) :: (Monad s) => DispatchFilter s a -> DispatchFilter s a -> DispatchFilter s a-f >--> f2 = \x -> f x >>= maybe (return Nothing) f2---- | A filter that always fails (i.e. no filtering)-nullFilter :: (Monad s) => DispatchFilter s a-nullFilter = return.Just---- | If the item meets some condition, use the first filter, otherwise--- use the second one.-condFilter :: (Monad s) => (a -> Bool)- -> DispatchFilter s a -> DispatchFilter s a- -> DispatchFilter s a-condFilter cond f1 f2 = \x -> if cond x then f1 x else f2 x-\end{code}--\subsection{Statistics}--\begin{code}-modifyStats :: (Metric -> Metric) -> BuilderState st ()-modifyStats fn = lift $ modify $ updateMetrics fn--incrCounter :: String -> Int -> BuilderState st ()-incrCounter key n = modifyStats (incrIntMetric key n)--queryCounter :: String -> Statistics -> Maybe Int-queryCounter key s =- case queryMetrics (queryIntMetric key) s of- [] -> Nothing- [c] -> Just c- _ -> geniBug $ "More than one instance of the metric: " ++ key-\end{code}--\subsection{Command line configuration}--\begin{code}-initStats :: Params -> Statistics-initStats pa =- let mdefault ms = if "default" `elem` ms then defaultMetricNames else []- identifyMs :: [String] -> [Metric]- identifyMs ms = map namedMetric $ mdefault ms ++ delete "default" ms- metrics = identifyMs $ fromMaybe [] $ getFlagP MetricsFlg pa- in execState (mapM addMetric metrics) emptyStats--namedMetric :: String -> Metric--- the default case is that it's an int metric-namedMetric n = IntMetric n 0---- Note that the strings here are command-line strings, not metric names!-defaultMetricNames :: [ String ]-defaultMetricNames = [ num_iterations, chart_size, num_comparisons ]-\end{code}--\subsection{Common counters}--These numbers allow us to keep track of how efficient our generator is-and where we are in the process (how many steps we've taken, etc)--\begin{code}-num_iterations, chart_size, num_comparisons :: String--num_iterations = "iterations"-chart_size = "chart_size"-num_comparisons = "comparisons"-\end{code}--\section{The null builder}--For the purposes of tracking certain statistics without interfering with the-lazy evaluation of the real builders. For example, one we would like to be-able to do is count the number of substitution and foot nodes in the lexical-selection. Doing so would in a real builder might cause it to walk entire-trees for ptoentially no good reason.--\begin{code}-nullBuilder :: Builder () (NullState ()) Params-nullBuilder = Builder- { NLP.GenI.Builder.init = initNullBuilder- , step = return ()- , stepAll = return ()- , finished = const True- , unpack = return []- , partial = return []- }--type NullState a = BuilderState () a---- | Running the null builder allows you to track certain statistics------ * sem_literals - number of literals in the input semantics------ * lex_trees - total number of lexically selected trees---- * lex_foot_nodes - total number of nodes of any sort in lexically selected trees------ * lex_subst_nodes - total number of sustitution nodes in lexically selected trees------ * lex_foot_nodes - total number of foot nodes in lexically selected trees------ * plex_... - same as the lex_ equivalent, but after polarity filtering-initNullBuilder :: Input -> Params -> ((), Statistics)-initNullBuilder input config =- let countsFor ts = (length ts, length nodes, length sn, length an)- where nodes = concatMap (flatten.ttree) ts- sn = [ n | n <- nodes, gtype n == Subs ]- an = [ n | n <- nodes, gtype n == Foot ]- --- (tsem,_,_) = inSemInput input- cands = map fst $ inCands input- (_,_,(_,_,aut,_)) = preInit input config- cands2 = concatMap concat $ automatonPathSets aut- --- countUp = do incrCounter "sem_literals" $ length tsem- --- incrCounter "lex_subst_nodes" snl- incrCounter "lex_foot_nodes" anl- incrCounter "lex_nodes" nl- incrCounter "lex_trees" tl- -- node count after polarities are taken into account- incrCounter "plex_subst_nodes" snl2- incrCounter "plex_foot_nodes" anl2- incrCounter "plex_nodes" nl2- incrCounter "plex_trees" tl2- where (tl , nl , snl , anl ) = countsFor cands- (tl2, nl2, snl2, anl2) = countsFor cands2- in runState (execStateT countUp ()) (initStats config)-\end{code}--% -----------------------------------------------------------------------% strictly API-ish bits-% ------------------------------------------------------------------------\ignore{-\begin{code}--- | The names of lexically selected chart items used in a derivation-lexicalSelection :: Derivation -> [String]-lexicalSelection = sort . nub . concatMap (\d -> [dsChild d, dsParent d])---- | A lemma plus its morphological features-data LemmaPlus = LemmaPlus { lpLemma :: String- , lpFeats :: Flist }- deriving (Show, Eq, Ord)---- | A sentence composed of 'LemmaPlus' instead of plain old words-type LemmaPlusSentence = [LemmaPlus]--instance JSON LemmaPlus where- readJSON j =- do jo <- fromJSObject `fmap` readJSON j- let field x = maybe (fail $ "Could not find: " ++ x) readJSON- $ lookup x jo- LemmaPlus <$> field "lemma"- <*> (parsecToJSON "lemma-features" geniFeats =<< field "lemma-features")- showJSON (LemmaPlus l fs) =- JSObject . toJSObject $ [ ("lemma", showJSON l)- , ("lemma-features", showJSON $ showFlist fs)- ]--parsecToJSON :: Monad m => String -> CharParser () b -> String -> m b-parsecToJSON description p str =- case runParser p () "" str of- Left err -> fail $ "Couldn't parse " ++ description ++ " because " ++ show err- Right res -> return res-\end{code}-}
− src/NLP/GenI/BuilderGui.lhs
@@ -1,34 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.--\begin{code}-module NLP.GenI.BuilderGui-where--import Graphics.UI.WX--import qualified NLP.GenI.Builder as B-import NLP.GenI.Geni (ProgStateRef, GeniResult)-import NLP.GenI.Configuration (Params)-import NLP.GenI.Statistics (Statistics)-\end{code}--\begin{code}-data BuilderGui = BuilderGui- { resultsPnl :: forall a . ProgStateRef -> (Window a) -> IO ([GeniResult],Statistics,Layout)- , debuggerPnl :: forall a . (Window a) -> Params -> B.Input -> String -> IO Layout }-\end{code}
+ src/NLP/GenI/Configuration.hs view
@@ -0,0 +1,735 @@+-- GenI surface realiser+-- Copyright (C) 2005 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE OverloadedStrings, ViewPatterns #-}+module NLP.GenI.Configuration+ ( Params(..)+ --+ , mainBuilderTypes+ , getFlagP, getListFlagP, modifyFlagP, setFlagP, hasFlagP, deleteFlagP, hasOpt+ , emptyParams, defineParams+ , treatArgs, treatArgsWithParams, usage, basicSections, optionsSections+ , processInstructions+ , optionsForStandardGenI+ , optionsForBasicStuff, optionsForOptimisation, optionsForMorphology, optionsForInputFiles+ , optionsForBuilder, optionsForTesting+ , helpOption, verboseOption, macrosOption, lexiconOption+ , nubBySwitches+ , noArg, reqArg, optArg+ , parseFlagWithParsec+ -- * configration files+ , readGlobalConfig, setLoggers+ -- re-exports+ , module System.Console.GetOpt+ , module NLP.GenI.Flag+ , Typeable+ )+where++import Control.Applicative ( (<$>), pure )+import Control.Arrow ( first )+import Control.Monad ( liftM )+import Data.Char ( toLower, isSpace )+import Data.List ( find, intersperse, nubBy )+import Data.Maybe ( fromMaybe, isNothing, fromJust )+import Data.Maybe ( listToMaybe, mapMaybe )+import Data.String ( IsString(..) )+import Data.Text ( Text )+import Data.Typeable ( Typeable )+import System.Directory ( getAppUserDataDirectory, doesFileExist )+import System.Environment ( getProgName )+import System.FilePath+import System.IO ( stderr )+import Text.ParserCombinators.Parsec ( runParser, CharParser )+import qualified Data.ByteString.Char8 as BC+import qualified Data.Map as Map+import qualified Data.Text as T+import qualified Data.Text.IO as T++import Data.Yaml.YamlLight+import System.Console.GetOpt+import System.Log.Formatter+import System.Log.Handler ( LogHandler, setFormatter )+import System.Log.Handler.Simple+import System.Log.Logger++import NLP.GenI.Flag+import NLP.GenI.General ( geniBug, fst3, snd3 )+import NLP.GenI.Parser ( geniFeats, tillEof )+import NLP.GenI.Morphology.Types ( MorphRealiser )+import NLP.GenI.Pretty+import NLP.GenI.Polarity.Types ( readPolarityAttrs )+import NLP.GenI.LexicalSelection ( LexicalSelector )++-- --------------------------------------------------------------------+-- Params+-- --------------------------------------------------------------------++-- | Holds the specification for how Geni should be run, its input+-- files, etc. This is the stuff that would normally be found in+-- the configuration file.+data Params = Params+ { grammarType :: GrammarType+ , builderType :: BuilderType+ -- | Can still be overridden with a morph command mind you+ , customMorph :: Maybe MorphRealiser+ -- | Lexical selection function+ -- (if you set this you may want to add 'PreAnchored' to the config)+ , customSelector :: Maybe LexicalSelector+ , geniFlags :: [Flag]+ }++{-+instance Show Params where+ show p = unlines+ [ unwords [ "GenI config :", show (grammarType p), show (builderType p), morph ]+ , unwords $ "GenI flags :" : map show (geniFlags p)+ ]+ where+ morph = "custom morph:" ++ show (isJust (customMorph p))+-}++-- | The default parameters configuration+emptyParams :: Params+emptyParams = Params+ { builderType = SimpleBuilder+ , grammarType = GeniHand+ , customMorph = Nothing+ , customSelector = Nothing+ , geniFlags = emptyFlags+ }++hasOpt :: Optimisation -> Params -> Bool+hasOpt o p = maybe False (elem o) $ getFlagP OptimisationsFlg p++hasFlagP :: (Typeable f, Typeable x) => (x -> f) -> Params -> Bool+hasFlagP f = hasFlag f . geniFlags++deleteFlagP :: (Typeable f, Typeable x) => (x -> f) -> Params -> Params+deleteFlagP f p = p { geniFlags = deleteFlag f (geniFlags p) }++modifyFlagP :: (Eq f, Typeable f, Typeable x)+ => (x -> f) -> (x -> x) -> Params -> Params+modifyFlagP f m p = p { geniFlags = modifyFlag f m (geniFlags p) }++setFlagP :: (Eq f, Typeable f, Typeable x)+ => (x -> f) -> x -> Params -> Params+setFlagP f v p = p { geniFlags = setFlag f v (geniFlags p) }++getFlagP :: (Typeable f, Typeable x)+ => (x -> f) -> Params -> Maybe x+getFlagP f = getFlag f . geniFlags++getListFlagP :: (Typeable f, Typeable x)+ => ([x] -> f) -> Params -> [x]+getListFlagP f = fromMaybe [] . getFlagP f++emptyFlags :: [Flag]+emptyFlags =+ [ Flag ViewCmdFlg "ViewTAG"+ , Flag DetectPolaritiesFlg $+ readPolarityAttrs defaultPolarityAttrs+ , Flag RootFeatureFlg $+ parseFlagWithParsec "default root feat" geniFeats defaultRootFeat+ ]++-- --------------------------------------------------------------------+-- Command line arguments+-- --------------------------------------------------------------------++type OptSection = (String,[OptDescr Flag],[String])++-- | Uses the GetOpt library to process the command line arguments.+-- Note that we divide them into basic and advanced usage.+optionsForStandardGenI :: [OptDescr Flag]+optionsForStandardGenI =+ nubBySwitches $ concatMap snd3 optionsSections+ ++ [ Option ['p'] [] (reqArg WeirdFlg id "CMD") "" ]+ -- TODO: what is this -p flag for, exactly? It's something+ -- related to how GenI runs within an app bundle. Can we+ -- do away with it?++basicSections :: [OptSection]+basicSections =+ map tweakBasic $ take 1 optionsSections+ where+ tweakBasic (x,y,z) = (x,y,z ++ ["See --help for more options"])++optionsSections :: [OptSection]+optionsSections =+ [ ("Core options", optionsForBasicStuff, example)+ , ("Input", optionsForInputFiles, [])+ , ("Output", optionsForOutput, [])+ , ("Algorithm",+ (nubBySwitches $ optionsForBuilder ++ optionsForOptimisation),+ usageForOptimisations)+ , ("Morphology", optionsForMorphology, [])+ , ("User interface", optionsForUserInterface, [])+ , ("Batch processing", optionsForTesting, [])+ ]+ where+ example =+ [ "Example:"+ , " geni -m examples/ej/mac -l examples/ej/lexicon -s examples/ej/suite"+ ]++getSwitches :: OptDescr a -> ([Char],[String])+getSwitches (Option s l _ _) = (s,l)++nubBySwitches :: [OptDescr a] -> [OptDescr a]+nubBySwitches = nubBy (\x y -> getSwitches x == getSwitches y)++-- GetOpt wrappers+noArg :: forall f . (Eq f, Typeable f)+ => (() -> f) -> ArgDescr Flag+noArg s = NoArg (Flag s ())++reqArg :: forall f x . (Eq f, Typeable f, Eq x, Typeable x)+ => (x -> f) -- ^ flag+ -> (String -> x) -- ^ string reader for flag (probably |id| if already a String)+ -> String -- ^ description+ -> ArgDescr Flag+reqArg s fn desc = ReqArg (\x -> Flag s (fn x)) desc++optArg :: forall f x . (Eq f, Typeable f, Eq x, Typeable x)+ => (x -> f) -- ^ flag+ -> x -- ^ default value+ -> (String -> x) -- ^ string reader (as in @reqArg@)+ -> String -- ^ description+ -> ArgDescr Flag+optArg s def fn desc = OptArg (\x -> Flag s (maybe def fn x)) desc++-- -------------------------------------------------------------------+-- Parsing command line arguments+-- -------------------------------------------------------------------++-- | Print out a GenI-style usage message with options divided into sections+usage :: [OptSection] -- ^ options+ -> String -- ^ prog name+ -> String+usage sections pname =+ let header = "Usage: " ++ pname ++ " [OPTION...]\n"+ body = unlines $ map usageSection sections+ in header ++ body++usageSection :: (String, [OptDescr Flag],[String]) -> String+usageSection (name, opts, comments) =+ usageInfo (unlines $ [bar,name, bar]) opts ++ mcomments+ where+ bar = replicate 72 '='+ mcomments = if null comments then [] else "\n" ++ unlines comments++treatArgs :: [OptDescr Flag] -> [String] -> IO Params+treatArgs options argv = treatArgsWithParams options argv emptyParams++treatArgsWithParams :: [OptDescr Flag] -> [String] -> Params -> IO Params+treatArgsWithParams options argv initParams =+ case getOpt Permute options argv of+ (os,_,[] )-> return $ defineParams os initParams+ (_,_,errs) -> do p <- getProgName+ ioError (userError $ concat errs ++ usage basicSections p)++defineParams :: [Flag] -> Params -> Params+defineParams flgs prms =+ (\p -> foldr setDefault p $ geniFlags prms)+ . (mergeFlagsP OptimisationsFlg)+ . (mergeFlagsP MetricsFlg)+ $ prms+ { geniFlags = flgs+ , builderType = fromFlags builderType BuilderFlg flgs+ , grammarType = fromFlags grammarType GrammarTypeFlg flgs+ }+ where+ setDefault (Flag f v) p =+ if hasFlagP f p then p else setFlagP f v p+ mergeFlagsP f p =+ if hasFlagP f p+ then setFlagP f (concat $ getAllFlags f flgs) p+ else p+ fromFlags default_ t fs =+ fromMaybe (default_ prms) (getFlag t fs)++-- --------------------------------------------------------------------+-- Basic options+-- --------------------------------------------------------------------++optionsForBasicStuff :: [OptDescr Flag]+optionsForBasicStuff =+ [ helpOption, verboseOption, noguiOption+ , macrosOption , lexiconOption, testSuiteOption+ , rootFeatureOption+ , outputOption+ ]++-- --------------------------------------------------------------------+-- Input files+-- --------------------------------------------------------------------++optionsForInputFiles :: [OptDescr Flag]+optionsForInputFiles =+ [ macrosOption+ , lexiconOption+ , tracesOption+ , testSuiteOption+ , fromStdinOption+ , morphInfoOption+ , instructionsOption+ , rankingOption+ , Option [] ["preselected"] (NoArg (Flag GrammarTypeFlg PreAnchored))+ "do NOT perform lexical selection - treat the grammar as the selection"+ ]++instructionsOption, macrosOption, lexiconOption, tracesOption :: OptDescr Flag++instructionsOption =+ Option [] ["instructions"] (reqArg InstructionsFileFlg id "FILE")+ "instructions file FILE"++macrosOption =+ Option ['t','m'] ["trees","macros"] (reqArg MacrosFlg id "FILE")+ "tree schemata file FILE (unanchored trees)"++lexiconOption =+ Option ['l'] ["lexicon"] (reqArg LexiconFlg id "FILE")+ "lexicon file FILE"++tracesOption =+ Option [] ["traces"] (reqArg TracesFlg id "FILE")+ "traces file FILE (list of traces to display)"++rankingOption :: OptDescr Flag+rankingOption =+ Option [] ["ranking"] (reqArg RankingConstraintsFlg id "FILE")+ "ranking constraints FILE (using Optimality Theory)"++-- --------------------------------------------------------------------+-- Output+-- --------------------------------------------------------------------++optionsForOutput :: [OptDescr Flag]+optionsForOutput =+ [ outputOption+ , Option [] ["dump"] (noArg DumpDerivationFlg)+ "print derivation information on stdout (JSON)"+ -- same as rankingOption but with output-centric help text+ , partialOption+ , Option [] ["ranking"] (reqArg RankingConstraintsFlg id "FILE")+ "use constraints in FILE to rank output"+ ]++partialOption :: OptDescr Flag+partialOption =+ Option [] ["partial"] (noArg PartialFlg)+ "return partial result(s) if no complete solution is found"++outputOption :: OptDescr Flag+outputOption =+ Option ['o'] ["output"] (reqArg OutputFileFlg id "FILE")+ "output file FILE (stdout if unset)"++-- --------------------------------------------------------------------+-- User interface+-- --------------------------------------------------------------------++optionsForUserInterface :: [OptDescr Flag]+optionsForUserInterface =+ [ noguiOption, helpOption, versionOption+ , Option [] ["viewcmd"] (reqArg ViewCmdFlg id "CMD")+ "XMG tree-view command"+ ]++noguiOption :: OptDescr Flag+noguiOption = Option [] ["nogui"] (noArg DisableGuiFlg)+ "disable graphical user interface"++helpOption :: OptDescr Flag+helpOption = Option [] ["help"] (noArg HelpFlg)+ "show full list of command line switches"++versionOption :: OptDescr Flag+versionOption = Option [] ["version"] (noArg VersionFlg)+ "display the version"++verboseOption :: OptDescr Flag+verboseOption = Option ['v'] ["verbose"] (noArg VerboseModeFlg)+ "verbose mode"++-- --------------------------------------------------------------------+-- Optimisations+-- --------------------------------------------------------------------++defaultPolarityAttrs :: String+defaultPolarityAttrs = "cat"++exampleRootFeat :: String+exampleRootFeat = "[cat:s inv:- mode:ind|subj wh:-]"++defaultRootFeat :: String+defaultRootFeat = "[cat:_]"++optionsForOptimisation :: [OptDescr Flag]+optionsForOptimisation =+ [ Option [] ["opts"]+ (reqArg OptimisationsFlg readOptimisations "LIST")+ "optimisations 'LIST' (--help for details)"+ , Option [] ["detect-pols"]+ (reqArg DetectPolaritiesFlg readPolarityAttrs "LIST")+ ("attributes 'LIST' (eg. \"cat idx V.tense\", default:" ++ show defaultPolarityAttrs ++ ")")+ , rootFeatureOption+ , maxResultsOption+ ]++rootFeatureOption :: OptDescr Flag+rootFeatureOption =+ Option ['r'] ["rootfeat"]+ (reqArg RootFeatureFlg readRF "FEATURE")+ ("root features 'FEATURE' (eg. "+ ++ prettyStr exampleRF ++ ", default: "+ ++ prettyStr defaultRF ++ ")")+ where+ exampleRF = readRF exampleRootFeat+ defaultRF = readRF defaultRootFeat+ readRF = parseFlagWithParsec "root feature" geniFeats++coreOptimisationCodes :: [(Optimisation,String,String)]+coreOptimisationCodes =+ [ (Polarised , "p", "polarity filtering")+ , (NoConstraints , "nc", "disable semantic constraints (anti-optimisation!)")+ ]++optimisationCodes :: [(Optimisation,String,String)]+optimisationCodes =+ coreOptimisationCodes +++ [ (PolOpts , "pol", equivalentTo polOpts)+ , (AdjOpts , "adj", equivalentTo adjOpts)+ ]+ where equivalentTo os = "equivalent to '" ++ (unwords $ map showOptCode os) ++ "'"++polOpts, adjOpts :: [Optimisation]+polOpts = [Polarised]+adjOpts = []++-- ---------------------------------------------------------------------+-- Optimisation usage info+-- ---------------------------------------------------------------------++lookupOpt:: Optimisation -> (String, String)+lookupOpt k =+ case find (\x -> k == fst3 x) optimisationCodes of+ Just (_, c, d) -> (c, d)+ Nothing -> geniBug $ "optimisation " ++ show k ++ " unknown"++showOptCode :: Optimisation -> String+showOptCode = fst.lookupOpt++describeOpt :: (Optimisation, String, String) -> String+describeOpt (_,k,d) = k ++ " - " ++ d++-- | Displays the usage text for optimisations.+-- It shows a table of optimisation codes and their meaning.+usageForOptimisations :: [String]+usageForOptimisations =+ [ "Optimisations must be passed in as a space-delimited list"+ , "(ex: --opt='p f-sem' for polarities and semantic filtering)"+ , ""+ , "Optimisations:"+ , " " ++ unlinesTab (map describeOpt coreOptimisationCodes)+ ]+ where unlinesTab l = concat (intersperse "\n " l)++-- ---------------------------------------------------------------------+-- Parsing optimisation stuff+-- ---------------------------------------------------------------------++-- | If we do not recognise a code, we output an error message. We+-- also take the liberty of expanding thematic codes like 'pol'+-- into the respective list of optimisations.+readOptimisations :: String -> [Optimisation]+readOptimisations str =+ case parseOptimisations str of+ Left ick -> error $ "Unknown optimisations: " ++ (unwords ick)+ Right os -> (addif PolOpts polOpts) . (addif AdjOpts adjOpts) $ os+ where addif t x o = if (t `elem` o) then x ++ o else o++-- | Returns |Left| for any codes we don't recognise, or+-- |Right| if everything is ok.+parseOptimisations :: String -> Either [String] [Optimisation]+parseOptimisations str =+ let codes = words str+ mopts = map lookupOptimisation codes+ in if any isNothing mopts+ then Left [ c | (c,o) <- zip codes mopts, isNothing o ]+ else Right $ map fromJust mopts++lookupOptimisation :: String -> Maybe Optimisation+lookupOptimisation code =+ liftM fst3 $ find (\x -> snd3 x == code) optimisationCodes++-- | TODO: This is a horrible and abusive use of 'error'+parseFlagWithParsec :: String -> CharParser () b -> String -> b+parseFlagWithParsec description p str =+ case runParser (tillEof p) () "" str of+ Left err -> error $ "Couldn't parse " ++ description ++ " because " ++ show err+ Right res -> res++-- --------------------------------------------------------------------+-- Builders+-- --------------------------------------------------------------------++optionsForBuilder :: [OptDescr Flag]+optionsForBuilder =+ [ Option ['b'] ["builder"] (reqArg BuilderFlg readBuilderType "BUILDER")+ ("use as realisation engine one of: " ++ (unwords $ map show mainBuilderTypes))+ , partialOption+ , maxStepsOption+ , maxResultsOption+ ]++mainBuilderTypes :: [BuilderType]+mainBuilderTypes =+ [ SimpleBuilder, SimpleOnePhaseBuilder+ ]++-- | Hint: compose with (map toLower) to make it case-insensitive+mReadBuilderType :: String -> Maybe BuilderType+mReadBuilderType "simple" = Just SimpleBuilder+mReadBuilderType "simple-2p" = Just SimpleBuilder+mReadBuilderType "simple-1p" = Just SimpleOnePhaseBuilder+mReadBuilderType _ = Nothing++-- | Is case-insensitive, error if unknown type+readBuilderType :: String -> BuilderType+readBuilderType b =+ case mReadBuilderType $ map toLower b of+ Just x -> x+ Nothing -> error $ "Unknown builder type " ++ b++-- --------------------------------------------------------------------+-- Testing and profiling+-- --------------------------------------------------------------------++fromStdinOption :: OptDescr Flag+fromStdinOption =+ Option [] ["from-stdin"] (noArg FromStdinFlg) "get testcase from stdin"++testSuiteOption :: OptDescr Flag+testSuiteOption =+ Option ['s'] ["testsuite"] (reqArg TestSuiteFlg id "FILE") "test suite FILE"++maxResultsOption :: OptDescr Flag+maxResultsOption =+ Option [] ["maxresults"] (reqArg MaxResultsFlg read "INT")+ "return as soon as at least INT results are found"++maxStepsOption :: OptDescr Flag+maxStepsOption =+ Option [] ["maxsteps"] (reqArg MaxStepsFlg read "INT")+ "abort and return any results found after INT steps"++optionsForTesting :: [OptDescr Flag]+optionsForTesting =+ [ testSuiteOption+ , fromStdinOption+ , Option [] ["testcase"]+ (reqArg (TestCaseFlg . T.pack) id "STRING")+ "run test case STRING"+ , Option [] ["timeout"] (reqArg TimeoutFlg read "SECONDS")+ "time out after SECONDS seconds"+ , maxResultsOption+ , maxStepsOption+ , Option [] ["metrics"] (optArg MetricsFlg ["default"] words "LIST")+ "keep track of performance metrics: (default: iterations comparisons chart_size)"+ , Option [] ["statsfile"] (reqArg StatsFileFlg id "FILE")+ "write performance data to file FILE (stdout if unset)"+ , Option [] ["batchdir"] (reqArg BatchDirFlg id "DIR")+ "batch process the test suite and save results to DIR"+ , Option [] ["earlydeath"] (noArg EarlyDeathFlg)+ "exit on first case with no results (batch processing) "+ ]++-- --------------------------------------------------------------------+-- Morphology+-- --------------------------------------------------------------------++optionsForMorphology :: [OptDescr Flag]+optionsForMorphology =+ [ morphInfoOption+ , Option [] ["morphcmd"] (reqArg MorphCmdFlg id "CMD")+ "morphological post-processor CMD (default: unset)"+ ]++morphInfoOption :: OptDescr Flag+morphInfoOption = Option [] ["morphinfo"] (reqArg MorphInfoFlg id "FILE")+ "morphological features FILE (default: unset)"++-- ====================================================================+-- Scripting GenI+-- ====================================================================++-- | Update the internal instructions list, test suite and case+-- according to the contents of an instructions file.+--+-- Basic approach+--+-- * we always have instructions: if no instructions file, is specified+-- we infer virtual instructions from the test suite flag+-- * the testsuite and testcase flags are focusing tools, they pick out+-- a subset from the instructions+processInstructions :: Params -> IO Params+processInstructions config = do+ instructions <- case getFlagP InstructionsFileFlg config of+ Nothing -> return fakeInstructions+ Just f -> instructionsFile `fmap` T.readFile f+ let updateInstructions = setFlagP TestInstructionsFlg instructions+ -- we have to set a test suite in case the user only supplies+ -- an instructions argument so that NLP.GenI.loadEverything+ -- knows that the user has given us a suite to load+ updateTestSuite p =+ if hasFlagP TestSuiteFlg p then p+ else case (fst `fmap` listToMaybe instructions) of+ Just s -> setFlagP TestSuiteFlg s p+ Nothing -> p+ return . updateTestSuite . updateInstructions $ config+ where+ fakeInstructions :: [Instruction]+ fakeInstructions =+ let cases = singleton <$> getFlagP TestCaseFlg config+ mkInstr xs = singleton (xs, cases)+ in maybe [] mkInstr $ getFlagP TestSuiteFlg config++instructionsFile :: Text -> [Instruction]+instructionsFile =+ mapMaybe inst . T.lines+ where+ inst l = case T.words (T.takeWhile (/= '%') l) of+ [] -> Nothing+ [f] -> Just (T.unpack f, Nothing)+ (f:cs) -> Just (T.unpack f, Just cs)++-- ====================================================================+-- Configuration file+-- ====================================================================++readGlobalConfig :: IO (Maybe YamlLight)+readGlobalConfig = do+ geniCfgDir <- getAppUserDataDirectory "geni"+ let globalCfg = geniCfgDir </> "config.yaml"+ hasCfg <- doesFileExist globalCfg+ if hasCfg then Just `fmap` parseYamlFile globalCfg + else return Nothing++data LoggerConfig = LoggerConfig { lcName :: String+ , lcPriority :: Priority+ , lcHandler :: LogTo+ , lcFormatter :: LogFmt+ }+ deriving Show++data LogTo = LogToFile FilePath | LogToErr+ deriving Show++data LogFmt = LogFmtNull | LogFmtSimple String+ deriving Show++logDefaultConfig :: String -> LoggerConfig+logDefaultConfig n = LoggerConfig+ { lcName = n+ , lcPriority = DEBUG+ , lcHandler = LogToErr+ , lcFormatter = LogFmtNull+ }++setLoggers :: YamlLight -> IO ()+setLoggers y = do+ -- it seems we need to explicitly create the root logger+ -- we set this to the lowest priority because we want the user to+ -- be able to set the priority on their loggers as low as they want + updateGlobalLogger "" $ setLevel DEBUG+ . setHandlers noHandlers+ mapM_ setGeniHandler $ fromMaybe [globalDefault] (loggerConfig y)+ where+ noHandlers :: [GenericHandler ()]+ noHandlers = []+ globalDefault = (logDefaultConfig "NLP.GenI") { lcPriority = INFO }++setGeniHandler :: LoggerConfig -> IO ()+setGeniHandler lc = do+ h <- flip setFormatter fmttr <$> handler (lcPriority lc)+ updateGlobalLogger (lcName lc) (setHandlers [h])+ where+ handler = case lcHandler lc of+ LogToFile f -> fileHandler f+ LogToErr -> streamHandler stderr+ --+ fmttr = case lcFormatter lc of+ LogFmtSimple str -> simpleLogFormatter str+ LogFmtNull -> nullFormatter++instance Read LogTo where+ readsPrec _ (dropPrefix "stderr" -> ("", x)) = [ (LogToErr, x) ]+ readsPrec p (dropPrefix "file" -> ("", x)) = map (first LogToFile) (readsQuotedStringPrec p x)+ readsPrec _ _ = []++instance Read LogFmt where+ readsPrec _ (dropPrefix "null" -> ("", x)) = [ (LogFmtNull, x) ]+ readsPrec p (dropPrefix "simple" -> ("", x)) = map (first LogFmtSimple) (readsQuotedStringPrec p x)+ readsPrec _ _ = []++readsQuotedStringPrec :: Int -> String -> [ (String, String) ]+readsQuotedStringPrec p x@(h:_) | isSpace h =+ case dropWhile isSpace x of+ xs@('"':_) -> readsPrec p xs+ (break isSpace -> y) | not (null (fst y)) -> [y]+ _ -> []+readsQuotedStringPrec _ _ = []++loggerConfig :: YamlLight -> Maybe [LoggerConfig]+loggerConfig yaml = lookupYL "logging" yaml+ >>= unSeq+ >>= mapM unMap+ >>= mapM readOne+ where+ readOne :: Map.Map YamlLight YamlLight -> Maybe LoggerConfig + readOne m = do+ let name = fromMaybe "NLP.GenI" (get Just "name" m)+ return $ updater "level" m (\x l -> l { lcPriority = x })+ . updater "handler" m (\x l -> l { lcHandler = x })+ . updater "format" m (\x l -> l { lcFormatter = x })+ $ logDefaultConfig name+ updater str m fn = maybe id fn (get maybeRead str m)+ get f x m = Map.lookup x m >>= unStr >>= (f . BC.unpack)++instance IsString YamlLight where+ fromString = YStr . fromString++-- ----------------------------------------------------------------------+--+-- ----------------------------------------------------------------------++singleton :: a -> [a]+singleton = pure++maybeRead :: Read a => String -> Maybe a+maybeRead s = case reads s of+ [(x, rest)] | all isSpace rest -> Just x+ _ -> Nothing++dropPrefix :: Eq a => [a] -> [a] -> ([a],[a])+dropPrefix (x:xs) (y:ys) | x == y = dropPrefix xs ys+dropPrefix left right = (left,right)
− src/NLP/GenI/Configuration.lhs
@@ -1,891 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.--\chapter{Command line arguments}--\begin{code}-{-# LANGUAGE ExistentialQuantification #-}-module NLP.GenI.Configuration- ( Params(..), GrammarType(..), BuilderType(..), Instruction, Flag- -- * flags- , BatchDirFlg(..)- , DetectPolaritiesFlg(..)- , DisableGuiFlg(..)- , DumpDerivationFlg(..)- , EarlyDeathFlg(..)- , ExtraPolaritiesFlg(..)- , FromStdinFlg(..)- , HelpFlg(..)- , InstructionsFileFlg(..)- , LexiconFlg(..)- , MacrosFlg(..)- , MetricsFlg(..)- , MorphCmdFlg(..)- , MorphInfoFlg(..)- , NoLoadTestSuiteFlg(..)- , OptimisationsFlg(..)- , OutputFileFlg(..)- , PartialFlg(..)- , RankingConstraintsFlg(..)- , RegressionTestModeFlg(..)- , RootFeatureFlg(..)- , RunUnitTestFlg(..)- , StatsFileFlg(..)- , TestCaseFlg(..)- , TestInstructionsFlg(..)- , TestSuiteFlg(..)- , TimeoutFlg(..)- , TracesFlg(..)- , VerboseModeFlg(..)- , VersionFlg(..)- , ViewCmdFlg(..)- --- , mainBuilderTypes- , getFlagP, getListFlagP, setFlagP, hasFlagP, deleteFlagP, hasOpt- , getFlag, setFlag, hasFlag- , Optimisation(..)- , emptyParams, defineParams- , treatArgs, treatArgsWithParams, usage, basicSections, optionsSections- , processInstructions- , optionsForStandardGenI- , optionsForBasicStuff, optionsForOptimisation, optionsForMorphology, optionsForInputFiles- , optionsForBuilder, optionsForTesting- , nubBySwitches- , noArg, reqArg, optArg- , parseFlagWithParsec- -- re-exports- , module System.Console.GetOpt- , Typeable- )-where-\end{code}--\ignore{-\begin{code}-import qualified Data.Map as Map-import qualified Data.Set as Set--import Control.Monad ( liftM )-import Data.Char ( toLower )-import Data.Maybe ( listToMaybe, mapMaybe )-import Data.Typeable ( Typeable, typeOf, cast )-import System.Console.GetOpt-import System.Environment ( getProgName )-import Data.List ( find, intersperse, nubBy )-import Data.Maybe ( catMaybes, fromMaybe, isNothing, fromJust )-import Text.ParserCombinators.Parsec ( runParser, CharParser )--import NLP.GenI.Btypes ( Flist, showFlist, )-import NLP.GenI.General ( geniBug, fst3, snd3, Interval )-import NLP.GenI.GeniParsers ( geniFeats, geniPolarities )-import NLP.GenI.PolarityTypes ( PolarityKey(..), PolarityAttr(..), readPolarityAttrs )-\end{code}-}--% ---------------------------------------------------------------------% Code for debugging. (should be latex-commented-% when not in use)-% ----------------------------------------------------------------------%\begin{code}-%import Debug.Trace-%\end{code}--% ---------------------------------------------------------------------% Params-% ----------------------------------------------------------------------\begin{code}--- | Holds the specification for how Geni should be run, its input--- files, etc. This is the stuff that would normally be found in--- the configuration file.-data Params = Prms{- grammarType :: GrammarType,- builderType :: BuilderType,- geniFlags :: [Flag]-} deriving (Show)--hasOpt :: Optimisation -> Params -> Bool-hasOpt o p = maybe False (elem o) $ getFlagP OptimisationsFlg p--hasFlagP :: (Typeable f, Typeable x) => (x -> f) -> Params -> Bool-deleteFlagP :: (Typeable f, Typeable x) => (x -> f) -> Params -> Params-setFlagP :: (Eq f, Show f, Show x, Typeable f, Typeable x) => (x -> f) -> x -> Params -> Params-getFlagP :: (Show f, Show x, Typeable f, Typeable x) => (x -> f) -> Params -> Maybe x-getListFlagP :: (Show f, Show x, Typeable f, Typeable x) => ([x] -> f) -> Params -> [x]--hasFlagP f = hasFlag f . geniFlags-deleteFlagP f p = p { geniFlags = deleteFlag f (geniFlags p) }-setFlagP f v p = p { geniFlags = setFlag f v (geniFlags p) }-getFlagP f = getFlag f . geniFlags-getListFlagP f = fromMaybe [] . getFlagP f--- | The default parameters configuration-emptyParams :: Params-emptyParams = Prms {- builderType = SimpleBuilder,- grammarType = GeniHand,- geniFlags = [ Flag ViewCmdFlg "ViewTAG"- , Flag DetectPolaritiesFlg (readPolarityAttrs defaultPolarityAttrs)- , Flag RootFeatureFlg (readRF defaultRootFeat)- ]-}- where readRF = parseFlagWithParsec "default root feature" geniFeats-\end{code}--% ---------------------------------------------------------------------\section{Command line arguments}-% ----------------------------------------------------------------------Command line arguments can be specified in the GNU style, for example-\texttt{--foo=bar} or \texttt{--foo bar}, or \texttt{-f bar} when a-short switch is available. For more information, type \texttt{geni---help}.---\begin{code}-type OptSection = (String,[OptDescr Flag],[String])---- | Uses the GetOpt library to process the command line arguments.--- Note that we divide them into basic and advanced usage.-optionsForStandardGenI :: [OptDescr Flag]-optionsForStandardGenI =- nubBySwitches $ concatMap snd3 optionsSections- ++ -- FIXME: weird mac stuff- [ Option ['p'] [] (reqArg WeirdFlg id "CMD") "" ]--basicSections :: [OptSection]-basicSections = map tweakBasic $ take 1 optionsSections- where- tweakBasic (x,y,z) = (x,y,z ++ ["See --help for more options"])--optionsSections :: [OptSection]-optionsSections =- [ ("Core options", optionsForBasicStuff, example)- , ("Input", optionsForInputFiles, [])- , ("Output", optionsForOutput, [])- , ("Algorithm",- (nubBySwitches $ optionsForBuilder ++ optionsForOptimisation),- usageForOptimisations)- , ("Morphology", optionsForMorphology, [])- , ("User interface", optionsForUserInterface, [])- , ("Batch processing", optionsForTesting, [])- ]- where- example = [ "Example:"- , " geni -m examples/ej/mac -l examples/ej/lexicon -s examples/ej/suite"- ]--getSwitches :: OptDescr a -> ([Char],[String])-getSwitches (Option s l _ _) = (s,l)--nubBySwitches :: [OptDescr a] -> [OptDescr a]-nubBySwitches = nubBy (\x y -> getSwitches x == getSwitches y)---- GetOpt wrappers-noArg :: forall f . (Eq f, Show f, Typeable f)- => (() -> f) -> ArgDescr Flag-noArg s = NoArg (Flag s ())--reqArg :: forall f x . (Eq f, Show f, Typeable f, Eq x, Show x, Typeable x)- => (x -> f) -- ^ flag- -> (String -> x) -- ^ string reader for flag (probably |id| if already a String)- -> String -- ^ description- -> ArgDescr Flag-reqArg s fn desc = ReqArg (\x -> Flag s (fn x)) desc--optArg :: forall f x . (Eq f, Show f, Typeable f, Eq x, Show x, Typeable x)- => (x -> f) -- ^ flag- -> x -- ^ default value- -> (String -> x) -- ^ string reader (as in @reqArg@)- -> String -- ^ description- -> ArgDescr Flag-optArg s def fn desc = OptArg (\x -> Flag s (maybe def fn x)) desc-\end{code}--\begin{code}--- ---------------------------------------------------------------------- Parsing command line arguments--- ----------------------------------------------------------------------- | Print out a GenI-style usage message with options divided into sections-usage :: [OptSection] -- ^ options- -> String -- ^ prog name- -> String-usage sections pname =- let header = "Usage: " ++ pname ++ " [OPTION...]\n"- body = unlines $ map usageSection sections- in header ++ body--usageSection :: (String, [OptDescr Flag],[String]) -> String-usageSection (name, opts, comments) =- usageInfo (unlines $ [bar,name, bar]) opts ++ mcomments- where- bar = replicate 72 '='- mcomments = if null comments then [] else "\n" ++ unlines comments--treatArgs :: [OptDescr Flag] -> [String] -> IO Params-treatArgs options argv = treatArgsWithParams options argv emptyParams--treatArgsWithParams :: [OptDescr Flag] -> [String] -> Params -> IO Params-treatArgsWithParams options argv initParams =- case getOpt Permute options argv of- (os,_,[] )-> return $ defineParams os initParams- (_,_,errs) -> do p <- getProgName- ioError (userError $ concat errs ++ usage basicSections p)--defineParams :: [Flag] -> Params -> Params-defineParams flgs prms =- (\p -> foldr setDefault p $ geniFlags prms)- . (mergeFlagsP OptimisationsFlg)- . (mergeFlagsP MetricsFlg)- $ prms- { geniFlags = flgs- , builderType = fromFlags builderType BuilderFlg flgs- , grammarType = fromFlags grammarType GrammarTypeFlg flgs- }- where- setDefault (Flag f v) p =- if hasFlagP f p then p else setFlagP f v p- mergeFlagsP f p =- if hasFlagP f p- then setFlagP f (concat $ getAllFlags f flgs) p- else p- fromFlags default_ t fs =- fromMaybe (default_ prms) (getFlag t fs)-\end{code}--\section{Options by theme}-\label{sec:fancy_parameters}--At the time of this writing (2009-09-25), it is highly unlikely that all the-options are documented here. See \verb!geni --help! for more details.--Note that you might see an option described in more than one place-because it falls into multiple categories.--% ---------------------------------------------------------------------\subsection{Basic options}-% -----------------------------------------------------------------------\begin{code}-optionsForBasicStuff :: [OptDescr Flag]-optionsForBasicStuff =- [ helpOption, verboseOption, noguiOption- , macrosOption , lexiconOption, testSuiteOption- , outputOption- ]-\end{code}--% ---------------------------------------------------------------------\subsection{Input files}-% ----------------------------------------------------------------------See Chapter \ref{cha:formats} for details on how to write these files.--\begin{description}-\item[macros]- The \verb!macros! switch is used to supply GenI with FB-LTAG tree- schemata.-\item[lexicon]- The \verb!lexicon! is used for lexical entries that point to the- macros-\item[suite]- The \verb!suite! provides test cases on which to run GenI-\item[ranking]- The \verb!ranking! switch allows you to specify a file containing- Optimality Theory style constraints which GenI will use to rank- its output. See Chapter \ref{cha:ranking} for more details on the format- and use of this file.-\end{description}--\begin{code}-optionsForInputFiles :: [OptDescr Flag]-optionsForInputFiles =- [ macrosOption- , lexiconOption- , tracesOption- , testSuiteOption- , fromStdinOption- , morphInfoOption- , instructionsOption- , rankingOption- , Option [] ["preselected"] (NoArg (Flag GrammarTypeFlg PreAnchored))- "do NOT perform lexical selection - treat the grammar as the selection"- ]--instructionsOption, macrosOption, lexiconOption, tracesOption :: OptDescr Flag--instructionsOption =- Option [] ["instructions"] (reqArg InstructionsFileFlg id "FILE")- "instructions file FILE"--macrosOption =- Option ['m'] ["macros"] (reqArg MacrosFlg id "FILE")- "tree schemata file FILE (unanchored trees)"--lexiconOption =- Option ['l'] ["lexicon"] (reqArg LexiconFlg id "FILE")- "lexicon file FILE"--tracesOption =- Option [] ["traces"] (reqArg TracesFlg id "FILE")- "traces file FILE (list of traces to display)"--rankingOption :: OptDescr Flag-rankingOption =- Option [] ["ranking"] (reqArg RankingConstraintsFlg id "FILE")- "ranking constraints FILE (using Optimality Theory)"-\end{code}--% ---------------------------------------------------------------------\subsection{Output}-% ----------------------------------------------------------------------\begin{code}-optionsForOutput :: [OptDescr Flag]-optionsForOutput =- [ outputOption- , Option [] ["dump"] (noArg DumpDerivationFlg)- "print derivation information on stdout (JSON)"- , Option [] ["partial"] (noArg PartialFlg)- "return partial result(s) if no complete solution is found"- -- same as rankingOption but with output-centric help text- , Option [] ["ranking"] (reqArg RankingConstraintsFlg id "FILE")- "use constraints in FILE to rank output"- ]--outputOption :: OptDescr Flag-outputOption =- Option ['o'] ["output"] (reqArg OutputFileFlg id "FILE")- "output file FILE (stdout if unset)"-\end{code}--% ---------------------------------------------------------------------\subsection{User interface}-% ----------------------------------------------------------------------\begin{code}-optionsForUserInterface :: [OptDescr Flag]-optionsForUserInterface =- [ noguiOption, helpOption, versionOption- , Option [] ["regression"] (noArg RegressionTestModeFlg)- "Run in regression testing mode (needs grammar, etc)"- , Option [] ["unit-tests"] (noArg RunUnitTestFlg)- "Run in unit testing mode (no arguments needed)"- , Option [] ["viewcmd"] (reqArg ViewCmdFlg id "CMD")- "XMG tree-view command"- ]--noguiOption :: OptDescr Flag-noguiOption = Option [] ["nogui"] (noArg DisableGuiFlg)- "disable graphical user interface"--helpOption :: OptDescr Flag-helpOption = Option [] ["help"] (noArg HelpFlg)- "show full list of command line switches"--versionOption :: OptDescr Flag-versionOption = Option [] ["version"] (noArg VersionFlg)- "display the version"--verboseOption :: OptDescr Flag-verboseOption = Option ['v'] ["verbose"] (noArg VerboseModeFlg)- "verbose mode"-\end{code}--% ---------------------------------------------------------------------\subsection{Optimisations}-% ----------------------------------------------------------------------\begin{description}-\item[opt]- The opt switch lets you specify a list of optimisations- that GenI should use, for example, \texttt{--opt='pol S i'}.- We associate each optimisation with a short code like 'i' for- ``index accessibility filtering''. This code is what the- user passes in, and is sometimes used by GenI to tell the- user which optimisations it's using. See \texttt{geni- --help} for more detail on the codes.-- Optimisations can be accumulated. For example, if you say something- like \texttt{--opt='foo bar' --opt='quux'} it is the same as saying- \texttt{--opt='foo bar quux'}.-- Note that we also have two special thematic codes ``pol'' and- ``adj'' which tell GenI that it should enable all the- polarity-related, and all the adjunction-related- optimisations respectively.--\item[detect-pols]- This tells GenI how to detect polarities in your grammar. You pass- this in in the form of a space-delimited string, where each word is either- an attribute or a ``restricted'' attribute. In lieu of an explanation,- here is an example: the string ``cat idx V.tense D.c'' tells GenI that- we should detect polarities on the ``cat'' and ``idx'' attribute- for all nodes and also on the ``tense'' attribute for all nodes- with the category ``V'' and the ``c'' attribute for all nodes with the- category ``D''.-- If your grammar comes with its own hand-written polarities, you can- suppress polarity detection altogether by supplying the empty string.-- Also, if you do not use this switch, the following defaults will be- used:--\begin{includecodeinmanual}-\begin{code}-defaultPolarityAttrs :: String-defaultPolarityAttrs = "cat"-\end{code}-\end{includecodeinmanual}--\item[rootfeat]- No results? Make sure your rootfeat are set correctly. GenI- will reject all sentences whose root category does not unify- with the rootfeat, the default of which is:-\begin{includecodeinmanual}-\begin{code}-defaultRootFeat :: String-defaultRootFeat = "[cat:s inv:- mode:ind|subj wh:-]"-\end{code}-\end{includecodeinmanual}-- You can set rootfeat to be empty (\verb![]!) if you want, in- which case the realiser proper will return all results; but- note that if you want to use polarity filtering, you must at- least specify a value for the \verb!cat! feature.--\item[extrapols]- Allows to to preset some polarities. There's not very much use for- this, in my opinion. Most likely, what you really want is rootfeat.-\end{description}--\begin{code}-optionsForOptimisation :: [OptDescr Flag]-optionsForOptimisation =- [ Option [] ["opts"]- (reqArg OptimisationsFlg readOptimisations "LIST")- "optimisations 'LIST' (--help for details)"- , Option [] ["detect-pols"]- (reqArg DetectPolaritiesFlg readPolarityAttrs "LIST")- ("attributes 'LIST' (eg. \"cat idx V.tense\", default:" ++ show defaultPolarityAttrs ++ ")")- , Option [] ["rootfeat"]- (reqArg RootFeatureFlg readRF "FEATURE")- ("root features 'FEATURE' (for polarities, default:"- ++ showFlist defaultRF ++ ")")- , Option [] ["extrapols"]- (reqArg ExtraPolaritiesFlg readPolarities "STRING")- "preset polarities (normally, you should use rootfeat instead)"- ]- where- defaultRF = getListFlagP RootFeatureFlg emptyParams- readRF = parseFlagWithParsec "root feature" geniFeats- readPolarities = parseFlagWithParsec "polarity string" geniPolarities--data Optimisation = PolOpts- | AdjOpts- | Polarised- | NoConstraints- | SemFiltered- | Iaf -- ^ one phase only!- | EarlyNa- deriving (Show,Eq,Typeable)--coreOptimisationCodes :: [(Optimisation,String,String)]-coreOptimisationCodes =- [ (Polarised , "p", "polarity filtering")- , (EarlyNa , "e-na", "detect null adjunction at earliest opportunity")- , (SemFiltered , "f-sem", "semantic filtering (two-phase only)")- , (Iaf , "i", "index accesibility filtering (one-phase only)")- , (NoConstraints , "nc", "disable semantic constraints (anti-optimisation!)")- ]--optimisationCodes :: [(Optimisation,String,String)]-optimisationCodes =- coreOptimisationCodes ++- [ (SemFiltered , "S", "semantic filtering (same as f-sem)")- , (PolOpts , "pol", equivalentTo polOpts)- , (AdjOpts , "adj", equivalentTo adjOpts)- ]- where equivalentTo os = "equivalent to '" ++ (unwords $ map showOptCode os) ++ "'"--polOpts, adjOpts :: [Optimisation]-polOpts = [Polarised]-adjOpts = [EarlyNa, SemFiltered]-\end{code}--\begin{code}--- ------------------------------------------------------------------------ Optimisation usage info--- -----------------------------------------------------------------------lookupOpt:: Optimisation -> (String, String)-lookupOpt k =- case find (\x -> k == fst3 x) optimisationCodes of- Just (_, c, d) -> (c, d)- Nothing -> geniBug $ "optimisation " ++ show k ++ " unknown"--showOptCode :: Optimisation -> String-showOptCode = fst.lookupOpt--describeOpt :: (Optimisation, String, String) -> String-describeOpt (_,k,d) = k ++ " - " ++ d---- | Displays the usage text for optimisations.--- It shows a table of optimisation codes and their meaning.-usageForOptimisations :: [String]-usageForOptimisations =- [ "Optimisations must be passed in as a space-delimited list"- , "(ex: --opt='p f-sem' for polarities and semantic filtering)"- , ""- , "Optimisations:"- , " " ++ unlinesTab (map describeOpt coreOptimisationCodes)- ]- where unlinesTab l = concat (intersperse "\n " l)-\end{code}--\begin{code}--- ------------------------------------------------------------------------ Parsing optimisation stuff--- ------------------------------------------------------------------------- | If we do not recognise a code, we output an error message. We--- also take the liberty of expanding thematic codes like 'pol'--- into the respective list of optimisations.-readOptimisations :: String -> [Optimisation]-readOptimisations str =- case parseOptimisations str of- Left ick -> error $ "Unknown optimisations: " ++ (unwords ick)- Right os -> (addif PolOpts polOpts) . (addif AdjOpts adjOpts) $ os- where addif t x o = if (t `elem` o) then x ++ o else o---- | Returns |Left| for any codes we don't recognise, or--- |Right| if everything is ok.-parseOptimisations :: String -> Either [String] [Optimisation]-parseOptimisations str =- let codes = words str- mopts = map lookupOptimisation codes- in if any isNothing mopts- then Left [ c | (c,o) <- zip codes mopts, isNothing o ]- else Right $ map fromJust mopts--lookupOptimisation :: String -> Maybe Optimisation-lookupOptimisation code =- liftM fst3 $ find (\x -> snd3 x == code) optimisationCodes--parseFlagWithParsec :: String -> CharParser () b -> String -> b-parseFlagWithParsec description p str =- case runParser p () "" str of- Left err -> error $ "Couldn't parse " ++ description ++ " because " ++ show err- Right res -> res-\end{code}--% ---------------------------------------------------------------------\subsection{Builders}-% ----------------------------------------------------------------------\begin{description}-\item[builder]- A builder is basically a surface realisation algorithm. \geni has the- infrastructure to support different realisation algorithms, but some- broken ones have been removed.-\end{description}--\begin{code}-data BuilderType = NullBuilder |- SimpleBuilder | SimpleOnePhaseBuilder- deriving (Eq, Typeable)--instance Show BuilderType where- show NullBuilder = "null"- show SimpleBuilder = "simple-2p"- show SimpleOnePhaseBuilder = "simple-1p"--optionsForBuilder :: [OptDescr Flag]-optionsForBuilder =- [ Option ['b'] ["builder"] (reqArg BuilderFlg readBuilderType "BUILDER")- ("use as realisation engine one of: " ++ (unwords $ map show mainBuilderTypes))- ]--mainBuilderTypes :: [BuilderType]-mainBuilderTypes =- [ SimpleBuilder, SimpleOnePhaseBuilder- ]---- | Hint: compose with (map toLower) to make it case-insensitive-mReadBuilderType :: String -> Maybe BuilderType-mReadBuilderType "null" = Just NullBuilder-mReadBuilderType "simple" = Just SimpleBuilder-mReadBuilderType "simple-2p" = Just SimpleBuilder-mReadBuilderType "simple-1p" = Just SimpleOnePhaseBuilder-mReadBuilderType _ = Nothing---- | Is case-insensitive, error if unknown type-readBuilderType :: String -> BuilderType-readBuilderType b =- case mReadBuilderType $ map toLower b of- Just x -> x- Nothing -> error $ "Unknown builder type " ++ b--\end{code}--% ---------------------------------------------------------------------\subsection{Testing and profiling}-% ----------------------------------------------------------------------\begin{code}-fromStdinOption :: OptDescr Flag-fromStdinOption =- Option [] ["from-stdin"] (noArg FromStdinFlg) "get testcase from stdin"--testSuiteOption :: OptDescr Flag-testSuiteOption =- Option ['s'] ["testsuite"] (reqArg TestSuiteFlg id "FILE") "test suite FILE"--optionsForTesting :: [OptDescr Flag]-optionsForTesting =- [ testSuiteOption- , fromStdinOption- , Option [] ["testcase"] (reqArg TestCaseFlg id "STRING")- "run test case STRING"- , Option [] ["timeout"] (reqArg TimeoutFlg read "SECONDS")- "time out after SECONDS seconds"- , Option [] ["metrics"] (optArg MetricsFlg ["default"] words "LIST")- "keep track of performance metrics: (default: iterations comparisons chart_size)"- , Option [] ["statsfile"] (reqArg StatsFileFlg id "FILE")- "write performance data to file FILE (stdout if unset)"- , Option [] ["batchdir"] (reqArg BatchDirFlg id "DIR")- "batch process the test suite and save results to DIR"- , Option [] ["earlydeath"] (noArg EarlyDeathFlg)- "exit on first case with no results (batch processing) "- ]-\end{code}--% ---------------------------------------------------------------------\subsection{Morphology}-% ----------------------------------------------------------------------GenI provides two options for morphology: either you use an external-inflection program (morphcmd), or you pass in a morphological lexicon-(morphlexicon) and in doing so, use GenI's built in inflecter. The-GenI internal morphology mechanism is a simple and stupid lookup-and--unify table, so you probably don't want to use it if you have a huge-lexicon.--\begin{description}-\item[morphcmd] specifies the program used for morphology. Literate-GenI \cite{literateGeni} has a chapter describing how that program must work.-It will mostly likely be a script you wrote to wrap around some off-the-shelf-software.-\item[morphlexicon] specifies a morphological lexicon for use by-GenI's internal morphological generator. Specifying this option will-cause the morphcmd flag to be ignored.-\item[morphinfo] tells GenI which literals in the input semantics are-to be used by the morphological \emph{pre-}processor. The pre-processor-strips these features from the input and fiddles with the elementary-trees used by GenI so that the right features get attached to the leaf-nodes. An example of a ``morphological'' literal is something like-\texttt{past(p)}.-\end{description}--\begin{code}-optionsForMorphology :: [OptDescr Flag]-optionsForMorphology =- [ morphInfoOption- , Option [] ["morphcmd"] (reqArg MorphCmdFlg id "CMD")- "morphological post-processor CMD (default: unset)"- ]--morphInfoOption :: OptDescr Flag-morphInfoOption = Option [] ["morphinfo"] (reqArg MorphInfoFlg id "FILE")- "morphological features FILE (default: unset)"-\end{code}--% ---------------------------------------------------------------------\subsection{Other options}-% ----------------------------------------------------------------------\begin{code}-data GrammarType = GeniHand -- ^ geni's text format- | PreCompiled -- ^ built into geni, no parsing needed- | PreAnchored -- ^ lexical selection already done- deriving (Show, Eq, Typeable)-\end{code}--% ====================================================================-\section{Scripting GenI}-% ====================================================================--\begin{description}-\item[instructions] An instructions file can be used to run GenI on-a list of test suites and cases.--Any input that you give to GenI will be interpreted as a list of test-suites (and test cases that you want to run). Each line has the format-\texttt{path/to/test-suite case1 case2 .. caseN}. You can omit the-test cases, which is interpreted as you wanting to run the entire test-suite. Also, the \verb!%! character and anything after is treated as-a comment.--Interaction with \verb!--testsuite! and \verb!--testcase!:-\begin{itemize}-\item If only \verb!--instructions! is set, then the first test suite- and or test case from the instructions file is used.-\item If only \verb!--testsuite! and \verb!--testcase! are set, we- pretend that an instructions file was supplied saying that we- want to run the entirety of the test suite specified in- \verb!--testsuite!.-\item If both \verb!--instructions! and \verb!--testsuite!/- \verb!--testcase! are set then the latter are used to- select from within the instructions.-\end{itemize}-\end{description}---\begin{code}-type Instruction = (FilePath, Maybe [String])---- | Update the internal instructions list, test suite and case--- according to the contents of an instructions file.-processInstructions :: Params -> IO Params-processInstructions config =- do instructions <- case getFlagP InstructionsFileFlg config of- Nothing -> return fakeInstructions- Just f -> instructionsFile `fmap` readFile f- -- basically set the test suite/case flag to the first instruction- -- note that with the above code (which sets the first instruction- -- to the test suite/case flag), this should work out to identity- -- when those flags are provided.- let updateInstructions =- setFlagP TestInstructionsFlg instructions- updateTestCase p =- if hasFlagP TestCaseFlg p then p- else case (listToMaybe instructions >>= snd >>= listToMaybe) of- Just c -> setFlagP TestCaseFlg c p - Nothing -> p- updateTestSuite p =- if hasFlagP TestSuiteFlg p then p- else case (fst `fmap` listToMaybe instructions) of- Just s -> setFlagP TestSuiteFlg s p- Nothing -> p- return . updateInstructions . updateTestSuite . updateTestCase $ config- where- fakeInstructions =- case getFlagP TestSuiteFlg config of- Just ts -> [ (ts, Nothing) ]- Nothing -> []--instructionsFile :: String -> [Instruction]-instructionsFile = mapMaybe inst . lines- where- inst l = case words (takeWhile (/= '%') l) of- [] -> Nothing- [f] -> Just (f, Nothing)- (f:cs) -> Just (f, Just cs)-\end{code}--% ====================================================================-% Flags-% ====================================================================--\begin{code}-{--Flags are GenI's internal representation of command line arguments. We-use phantom existential types (?) for representing GenI flags. This-makes it simpler to do things such as ``get the value of the MacrosFlg''-whilst preserving type safety (we always know that MacrosFlg is-associated with String). The alternative would be writing getters and-setters for each flag, and that gets really boring after a while.--}--data Flag = forall f x . (Eq f, Show f, Show x, Typeable f, Typeable x) =>- Flag (x -> f) x deriving (Typeable)--instance Show Flag where- show (Flag f x) = "Flag " ++ show (f x)--instance Eq Flag where- (Flag f1 x1) == (Flag f2 x2)- | (typeOf f1 == typeOf f2) && (typeOf x1 == typeOf x2) =- (fromJust . cast . f1 $ x1) == (f2 x2)- | otherwise = False--isFlag :: (Typeable f, Typeable x) => (x -> f) -> Flag -> Bool-hasFlag :: (Typeable f, Typeable x) => (x -> f) -> [Flag] -> Bool-deleteFlag :: (Typeable f, Typeable x) => (x -> f) -> [Flag] -> [Flag]-setFlag :: (Eq f, Show f, Show x, Typeable f, Typeable x) => (x -> f) -> x -> [Flag] -> [Flag]-getFlag :: (Show f, Show x, Typeable f, Typeable x) => (x -> f) -> [Flag] -> Maybe x-getAllFlags :: (Show f, Show x, Typeable f, Typeable x) => (x -> f) -> [Flag] -> [x]--isFlag f1 (Flag f2 _) = typeOf f1 == typeOf f2-hasFlag f = any (isFlag f)-deleteFlag f = filter (not.(isFlag f))-setFlag f v fs = (Flag f v) : tl where tl = deleteFlag f fs-getFlag f fs = do (Flag _ v) <- find (isFlag f) fs ; cast v-getAllFlags f fs = catMaybes [ cast v | flg@(Flag _ v) <- fs, isFlag f flg ]---{--Below are just the individual flags, which unfortunately have to be-defined as separate data types because of our fancy existential-data type code.--}--- input files-#define FLAG(x,y) data x = x y deriving (Eq, Show, Typeable)--FLAG (BatchDirFlg, FilePath)-FLAG (DisableGuiFlg, ())-FLAG (DetectPolaritiesFlg, (Set.Set PolarityAttr))-FLAG (DumpDerivationFlg, ())-FLAG (EarlyDeathFlg, ())-FLAG (ExtraPolaritiesFlg, (Map.Map PolarityKey Interval))-FLAG (FromStdinFlg, ())-FLAG (HelpFlg, ())-FLAG (InstructionsFileFlg, FilePath)-FLAG (LexiconFlg, FilePath)-FLAG (MacrosFlg, FilePath)-FLAG (TracesFlg, FilePath)-FLAG (MetricsFlg, [String])-FLAG (MorphCmdFlg, String)-FLAG (MorphInfoFlg, FilePath)-FLAG (OptimisationsFlg, [Optimisation])-FLAG (OutputFileFlg, String)-FLAG (PartialFlg, ())-FLAG (RankingConstraintsFlg, FilePath)-FLAG (RegressionTestModeFlg, ())-FLAG (RootFeatureFlg, Flist)-FLAG (RunUnitTestFlg, ())-FLAG (NoLoadTestSuiteFlg, ())-FLAG (StatsFileFlg, FilePath)-FLAG (TestCaseFlg, String)-FLAG (TestInstructionsFlg, [Instruction])-FLAG (TestSuiteFlg, FilePath)-FLAG (TimeoutFlg, Integer)-FLAG (VerboseModeFlg, ())-FLAG (VersionFlg, ())-FLAG (ViewCmdFlg, String)--- not to be exported (defaults)--- the WeirdFlg exists strictly to please OS X when you launch--- GenI in an application bundle (double-click)... for some--- reason it wants to pass an argument to -p-FLAG (BuilderFlg, BuilderType)-FLAG (GrammarTypeFlg, GrammarType)-FLAG (WeirdFlg, String)-\end{code}--
src/NLP/GenI/Console.hs view
@@ -18,51 +18,98 @@ -- | The console user interface including batch processing on entire -- test suites. -module NLP.GenI.Console(consoleGeni, runTestCaseOnly) where+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE OverloadedStrings #-}+module NLP.GenI.Console ( consoleGeni, loadNextSuite ) where +import Control.Applicative ( pure, (<$>) ) import Control.Monad import Data.IORef(readIORef, modifyIORef)-import Data.List(find, sort)-import Data.Maybe ( isJust, fromMaybe )-import System.Directory(createDirectoryIfMissing)-import System.Exit ( exitFailure )+import Data.List ( find, partition )+import Data.Maybe ( fromMaybe, isJust )+import Data.Text ( Text )+import Data.Time ( getCurrentTime, formatTime )+import Data.Typeable+import System.Log.Logger+import System.Locale ( defaultTimeLocale, iso8601DateFormat )+import System.Directory( createDirectoryIfMissing, getTemporaryDirectory )+import System.Exit ( exitWith, exitFailure, ExitCode(..) ) import System.FilePath ( (</>), takeFileName )+import System.IO ( stderr )+import System.Timeout ( timeout )+import qualified Data.ByteString as B+import qualified Data.Text as T+import qualified Data.Text.IO as T+import qualified Data.Text.Encoding as T -import NLP.GenI.Btypes- ( SemInput, TestCase(tcSem, tcName)- )-import qualified NLP.GenI.Btypes as G+ import NLP.GenI.General- ( ePutStr, ePutStrLn, withTimeout, exitTimeout+ ( ePutStr, ePutStrLn, )-import NLP.GenI.Geni+import NLP.GenI import NLP.GenI.Configuration ( Params- , BatchDirFlg(..), DumpDerivationFlg(..), EarlyDeathFlg(..), FromStdinFlg(..), OutputFileFlg(..)- , MetricsFlg(..), RankingConstraintsFlg(..), StatsFileFlg(..)+ , BatchDirFlg(..), DumpDerivationFlg(..), EarlyDeathFlg(..)+ , MetricsFlg(..), RankingConstraintsFlg(..) , TestCaseFlg(..), TestSuiteFlg(..), TestInstructionsFlg(..)+ , FromStdinFlg(..), OutputFileFlg(..), StatsFileFlg(..) , TimeoutFlg(..), VerboseModeFlg(..) , hasFlagP, getListFlagP, getFlagP, setFlagP , builderType , BuilderType(..) )-import qualified NLP.GenI.Builder as B+import NLP.GenI.General ( mkLogname )+import NLP.GenI.Pretty+import NLP.GenI.Semantics ( SemInput ) import NLP.GenI.Simple.SimpleBuilder-import NLP.GenI.Statistics ( Statistics )+import NLP.GenI.TestSuite ( TestCase(..) ) import Text.JSON import Text.JSON.Pretty ( render, pp_value ) consoleGeni :: ProgStateRef -> IO() consoleGeni pstRef = do- pst <- readIORef pstRef- loadEverything pstRef- case getFlagP TimeoutFlg (pa pst) of- Nothing -> runInstructions pstRef- Just t -> withTimeout t (timeoutErr t) $ runInstructions pstRef- where- timeoutErr t = do ePutStrLn $ "GenI timed out after " ++ (show t) ++ "s"- exitTimeout+ config <- pa <$> readIORef pstRef+ loadEverything pstRef+ let job | hasFlagP FromStdinFlg config = runStdinTestCase pstRef+ | hasFlagP BatchDirFlg config = runInstructions pstRef -- even if there is a testcase+ | Just tc <- getFlagP TestCaseFlg config = runSpecificTestCase pstRef tc+ | otherwise = runInstructions pstRef+ case getFlagP TimeoutFlg config of+ Nothing -> job+ Just t -> withGeniTimeOut t job +withGeniTimeOut :: Int -- ^ seconds+ -> IO ()+ -> IO ()+withGeniTimeOut t job = do+ status <- timeout (fromIntegral t * 1000000) job+ case status of+ Just () -> return ()+ Nothing -> do+ ePutStrLn $ "GenI timed out after " ++ show t ++ "s"+ exitWith (ExitFailure 2)++-- | Run GenI without reading any test suites, just grab semantics from stdin+runStdinTestCase :: ProgStateRef -> IO ()+runStdinTestCase pstRef = do+ config <- pa <$> readIORef pstRef+ mSemInput <- parseSemInput <$> getContents+ case mSemInput of+ Left err ->+ fail $ "I didn't understand the semantics you gave me: " ++ show err+ Right semInput ->+ runOnSemInput pstRef (runAsStandalone config) semInput >> return ()++-- | Run a test case with the specified name+runSpecificTestCase :: ProgStateRef -> Text -> IO ()+runSpecificTestCase pstRef cname = do+ config <- pa <$> readIORef pstRef+ fullsuite <- loadTestSuite pstRef+ case find (\x -> tcName x == cname) fullsuite of+ Nothing -> fail ("No such test case: " ++ T.unpack cname)+ Just s -> runOnSemInput pstRef (runAsStandalone config) (tcSem s) >> return ()+ -- | Runs the tests specified in our instructions list. -- We assume that the grammar and lexicon are already -- loaded into the monadic state.@@ -72,123 +119,165 @@ runInstructions pstRef = do pst <- readIORef pstRef let config = pa pst- case getFlagP BatchDirFlg config of- Nothing -> runTestCaseOnly pstRef >> return ()- Just bdir -> runBatch bdir+ batchDir <- case getFlagP BatchDirFlg config of+ Nothing -> do+ t <- getTemporaryDirectory+ utc <- fmtTime <$> getCurrentTime+ return (t </> "geni-" ++ utc)+ Just bdir -> return bdir+ runBatch batchDir+ unless (hasFlagP BatchDirFlg config) $ do+ ePutStr $ unlines [ ""+ , "Results saved to directory " ++ batchDir+ , "To save results in a different directory, use the --batchdir flag"+ ] where- runBatch bdir =- do config <- pa `fmap` readIORef pstRef- mapM_ (runSuite bdir) $ getListFlagP TestInstructionsFlg config- runSuite bdir (file, mtcs) =- do modifyIORef pstRef $ \p -> p { pa = setFlagP TestSuiteFlg file (pa p) }- config <- pa `fmap` readIORef pstRef+ fmtTime = formatTime defaultTimeLocale (iso8601DateFormat (Just "%H%M"))+ runBatch bdir = do+ config <- pa <$> readIORef pstRef+ mapM_ (runSuite bdir) $+ getListFlagP TestInstructionsFlg config+ runSuite bdir next@(file, _) =+ do suite <- loadNextSuite pstRef next -- we assume the that the suites have unique filenames let bsubdir = bdir </> takeFileName file- createDirectoryIfMissing False bsubdir- fullsuite <- loadTestSuite pstRef- let suite = case (mtcs, getFlagP TestCaseFlg config) of- (_, Just c) -> filter (\t -> tcName t == c) fullsuite- (Nothing,_) -> fullsuite- (Just cs,_) -> filter (\t -> tcName t `elem` cs) fullsuite- if any null $ map tcName suite+ createDirectoryIfMissing True bsubdir+ if any (T.null . tcName) suite then fail $ "Can't do batch processing. The test suite " ++ file ++ " has cases with no name." else do ePutStrLn "Batch processing mode" mapM_ (runCase bsubdir) suite- runCase bdir (G.TestCase { tcName = n, tcSem = s }) =+ runCase bdir (TestCase { tcName = n, tcSem = s }) = do config <- pa `fmap` readIORef pstRef let verbose = hasFlagP VerboseModeFlg config earlyDeath = hasFlagP EarlyDeathFlg config when verbose $ ePutStrLn "======================================================"- (res , _) <- runOnSemInput pstRef (PartOfSuite n bdir) s- ePutStrLn $ " " ++ n ++ " - " ++ (show $ length res) ++ " results"+ gresults <- runOnSemInput pstRef (PartOfSuite n bdir) s+ let res = grResults gresults+ (goodres, badres) = partition isSuccess (grResults gresults)+ T.hPutStrLn stderr $+ " " <> n <+> "-" <+> pretty (length goodres) <+> "results" <+>+ parens (pretty (length badres)) when (null res && earlyDeath) $ do- ePutStrLn $ "Exiting early because test case " ++ n ++ " failed."- exitFailure+ T.hPutStrLn stderr $ "Exiting early because test case" <+> n <+> "failed."+ exitFailure --- | Run the specified test case, or failing that, the first test--- case in the suite-runTestCaseOnly :: ProgStateRef -> IO ([GeniResult], Statistics)-runTestCaseOnly pstRef =- do pst <- readIORef pstRef- let config = pa pst- pstOutfile = fromMaybe "" $ getFlagP OutputFileFlg config- sFile = fromMaybe "" $ getFlagP StatsFileFlg config- semInput <- case getFlagP TestCaseFlg config of- Nothing -> if hasFlagP FromStdinFlg config- then do getContents >>= loadTargetSemStr pstRef- ts `fmap` readIORef pstRef- else getFirstCase pst- Just c -> findCase pst c- runOnSemInput pstRef (Standalone pstOutfile sFile) semInput- where- getFirstCase pst =- case tsuite pst of- [] -> fail "Test suite is empty."- (c:_) -> return $ tcSem c- findCase pst theCase =- case find (\x -> tcName x == theCase) (tsuite pst) of- Nothing -> fail ("No such test case: " ++ theCase)- Just s -> return $ tcSem s+-- | Used in processing instructions files. Each instruction consists of a+-- suite file and a list of test case names from that file+--+-- See <http://projects.haskell.org/GenI/manual/command-line.html> for+-- how testsuite, testcase, and instructions are expected to interact+--+-- (Exported for use by regression testing code)+loadNextSuite :: ProgStateRef -> (FilePath, Maybe [Text]) -> IO [TestCase]+loadNextSuite pstRef (file, mtcs) = do+ debugM logname $ "Loading next test suite: " ++ file+ debugM logname $ "Test case filter: " ++ maybe "none" (\xs -> show (length xs) ++ " items") mtcs+ modifyIORef pstRef $ \p -> p { pa = setFlagP TestSuiteFlg file (pa p) } -- yucky statefulness! :-(+ config <- pa `fmap` readIORef pstRef+ let mspecific = getFlagP TestCaseFlg config+ debugM logname . T.unpack $ "Test case to pick out:" <+> fromMaybe "none" mspecific+ fullsuite <- loadTestSuite pstRef+ return (filterSuite mtcs mspecific fullsuite)+ where+ filterSuite _ (Just c) suite = filter (\t -> tcName t == c) suite+ filterSuite Nothing Nothing suite = suite+ filterSuite (Just cs) Nothing suite = filter (\t -> tcName t `elem` cs) suite data RunAs = Standalone FilePath FilePath- | PartOfSuite String FilePath+ | PartOfSuite Text FilePath +runAsStandalone :: Params -> RunAs+runAsStandalone config =+ Standalone (fromMaybe "" $ getFlagP OutputFileFlg config)+ (fromMaybe "" $ getFlagP StatsFileFlg config)+ -- | Runs a case in the test suite. If the user does not specify any test -- cases, we run the first one. If the user specifies a non-existing -- test case we raise an error. runOnSemInput :: ProgStateRef -> RunAs -> SemInput- -> IO ([GeniResult], Statistics)-runOnSemInput pstRef args semInput =- do modifyIORef pstRef (\x -> x{ts = semInput, warnings = []})- pst <- readIORef pstRef- let config = pa pst- dump = hasFlagP DumpDerivationFlg config- useRanking = hasFlagP RankingConstraintsFlg config- (results, stats) <- case builderType config of- NullBuilder -> helper B.nullBuilder- SimpleBuilder -> helper simpleBuilder_2p- SimpleOnePhaseBuilder -> helper simpleBuilder_1p- warningsOut <- warnings `fmap` readIORef pstRef- -- create directory if need be- case args of- PartOfSuite n f -> createDirectoryIfMissing False (f </> n)- _ -> return ()- let oWrite = case args of- Standalone "" _ -> putStrLn- Standalone f _ -> writeFile f- PartOfSuite n f -> writeFile $ f </> n </> "responses"- doWrite = case args of- Standalone _ _ -> const (return ())- PartOfSuite n f -> writeFile $ f </> n </> "derivations"- soWrite = case args of- Standalone _ "" -> putStrLn- Standalone _ f -> writeFile f- PartOfSuite n f -> writeFile $ f </> n </> "stats"- --- if dump- then oWrite . ppJSON $ results- else if useRanking- then oWrite . unlines . map (prettyResult pst) $ results- else oWrite . unlines . sort . concatMap grRealisations $ results- doWrite . ppJSON $ results- -- print any warnings we picked up along the way- when (not $ null warningsOut) $- do let ws = reverse warningsOut- ePutStr $ "Warnings:\n" ++ (unlines $ map (\x -> " - " ++ x) ws)- case args of- PartOfSuite n f -> writeFile (f </> n </> "warnings") $ unlines ws- _ -> return ()- -- print out statistical data (if available)- when (isJust $ getFlagP MetricsFlg config) $ soWrite (ppJSON stats)- --- return (results, stats)+ -> IO GeniResults+runOnSemInput pstRef args semInput = do+ pst <- readIORef pstRef+ case builderType (pa pst) of+ SimpleBuilder -> helper pst simpleBuilder_2p+ SimpleOnePhaseBuilder -> helper pst simpleBuilder_1p where- ppJSON :: JSON a => a -> String- ppJSON = render . pp_value . showJSON - helper builder =- do (results, stats, _) <- runGeni pstRef builder- return (results, stats)+ helper pst builder = do+ (res,_) <- runGeni pstRef semInput builder+ writeResults pst args semInput res+ return res +-- | Not just the global warnings but the ones local to each response too+allWarnings :: GeniResults -> [Text]+allWarnings res = concat $ grGlobalWarnings res+ : [ grWarnings s | GSuccess s <- grResults res ]++writeResults :: ProgState -> RunAs -> SemInput -> GeniResults -> IO ()+writeResults pst args semInput gresults = do+ -- create output directory as needed+ case args of+ PartOfSuite n f -> createDirectoryIfMissing True (f </> T.unpack n)+ _ -> return ()+ -- print responses+ if dump+ then writeResponses $ ppJSON results+ else writeResponses $ T.unlines . concatMap (fromResult formatResponses) $ results+ -- print out statistical data (if available)+ when (isJust $ getFlagP MetricsFlg config) $+ writeStats (ppJSON stats)+ -- print any warnings we picked up along the way+ unless (null warnings) $ do+ T.hPutStrLn stderr $ "Warnings:\n" <> formatWarnings warnings+ writeBatchFile "warnings" $ T.unlines warnings+ -- other outputs when run in batch mode+ writeBatchFile "semantics" $ pretty semInput+ writeBatchFile "derivations"$ ppJSON results+ where+ results = grResults gresults+ warnings = allWarnings gresults+ stats = grStatistics gresults+ config = pa pst+ dump = hasFlagP DumpDerivationFlg config+ -- do we print ranking information and all that other jazz?+ formatResponses = if hasFlagP RankingConstraintsFlg config+ then pure . prettyResult pst+ else grRealisations+ formatWarnings = T.unlines . map (" - " <>)+ --+ writeBatchFile key = case args of+ Standalone _ _ -> const (return ())+ PartOfSuite n f -> writeFileUtf8 (f </> T.unpack n </> key)+ writeResponses = case args of+ Standalone "" _ -> putStrLnUtf8+ Standalone f _ -> writeFileUtf8 f+ PartOfSuite _ _ -> writeBatchFile "responses"+ writeStats = case args of+ Standalone _ "" -> putStrLnUtf8+ Standalone _ f -> writeFileUtf8 f+ PartOfSuite _ _ -> writeBatchFile "stats"+ --+ fromResult :: (GeniSuccess -> [Text]) -> GeniResult -> [Text]+ fromResult _ (GError errs) = [ pretty errs ]+ fromResult f (GSuccess x) = f x++-- | TODO: If somebody puts together a render function that emits Data.Text+-- we should just use that instead+ppJSON :: JSON a => a -> Text+ppJSON = T.pack . render . pp_value . showJSON++writeFileUtf8 :: FilePath -> Text -> IO ()+writeFileUtf8 f = B.writeFile f . T.encodeUtf8++putStrLnUtf8 :: Text -> IO ()+putStrLnUtf8 = B.putStr . T.encodeUtf8 . (<> "\n")++-- ----------------------------------------------------------------------+-- Odds and ends+-- ----------------------------------------------------------------------++data MNAME = MNAME deriving Typeable+logname :: String+logname = mkLogname MNAME
+ src/NLP/GenI/FeatureStructure.hs view
@@ -0,0 +1,186 @@+-- GenI surface realiser+-- Copyright (C) 2005-2009 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE FlexibleInstances, TypeSynonymInstances, MultiParamTypeClasses #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}+module NLP.GenI.FeatureStructure where++import Data.Binary+import Data.Function (on)+import Data.Generics (Data)+import Data.List (sortBy)+import qualified Data.Map as Map+import Data.Typeable (Typeable)+import Data.Text ( Text )+import qualified Data.Text as T++import NLP.GenI.GeniShow+import NLP.GenI.GeniVal+import NLP.GenI.General ( geniBug )+import NLP.GenI.Pretty++import Control.DeepSeq++-- ----------------------------------------------------------------------+-- Core types+-- ----------------------------------------------------------------------++type Flist a = [AvPair a]+data AvPair a = AvPair { avAtt :: Text+ , avVal :: a }+ deriving (Ord, Eq, Data, Typeable)++-- experimental, alternative representation of Flist+-- which guarantees uniqueness of keys+type FeatStruct a = Map.Map Text a++emptyFeatStruct :: FeatStruct a+emptyFeatStruct = Map.empty++mkFeatStruct :: Flist GeniVal -> FeatStruct GeniVal +mkFeatStruct fs = Map.fromListWith oops . map fromPair $ fs+ where+ fromPair (AvPair a v) = (a,v)+ oops _ _ = geniBug $+ "I've allowed a feature structure with multiple versions of a key"+ ++ " to sneak through: " ++ prettyStr fs++fromFeatStruct :: FeatStruct a -> Flist a+fromFeatStruct = sortFlist . map (uncurry AvPair) . Map.toList++-- if we decide to move over to this representation of feature structures+-- we can get rid of showFlist, etc and probably just use toAscList+instance Pretty (FeatStruct GeniVal) where+ pretty = pretty . fromFeatStruct++instance GeniShow (FeatStruct GeniVal) where+ geniShowText = geniShowText . fromFeatStruct++-- ----------------------------------------------------------------------+-- Basic functions+-- ----------------------------------------------------------------------++-- | Sort an Flist according with its attributes+sortFlist :: Flist a -> Flist a+sortFlist = sortBy (compare `on` avAtt)++-- Traversal++instance DescendGeniVal v => DescendGeniVal (AvPair v) where+ descendGeniVal s (AvPair a v) = {-# SCC "descendGeniVal" #-} AvPair a (descendGeniVal s v)++instance DescendGeniVal a => DescendGeniVal (String, a) where+ descendGeniVal s (n,v) = {-# SCC "descendGeniVal" #-} (n,descendGeniVal s v)++instance DescendGeniVal v => DescendGeniVal ([String], Flist v) where+ descendGeniVal s (a,v) = {-# SCC "descendGeniVal" #-} (a, descendGeniVal s v)++instance Collectable a => Collectable (AvPair a) where+ collect (AvPair _ b) = collect b++-- Pretty printing and output format++instance Pretty (Flist GeniVal) where+ pretty = geniShowText++instance Pretty (AvPair GeniVal) where+ pretty = geniShowText++instance GeniShow (Flist GeniVal) where+ geniShowText = squares . T.unwords . map geniShowText++instance GeniShow (AvPair GeniVal) where+ geniShowText (AvPair a v) = a `T.append` ":" `T.append` geniShowText v++{-+instance Show (AvPair GeniVal) where+ show = showAv+-}++-- --------------------------------------------------------------------+-- Feature structure unification+-- --------------------------------------------------------------------++-- | 'unifyFeat' performs feature structure unification, under the+-- these assumptions about the input:+--+-- * Features are ordered+--+-- * The Flists do not share variables (renaming has already+-- been done.+--+-- The features are allowed to have different sets of attributes,+-- beacuse we use 'alignFeat' to realign them.+unifyFeat :: Monad m => Flist GeniVal -> Flist GeniVal -> m (Flist GeniVal, Subst)+unifyFeat f1 f2 =+ {-# SCC "unification" #-}+ let (att, val1, val2) = unzip3 $ alignFeat f1 f2+ in att `seq`+ do (res, subst) <- unify val1 val2+ return (zipWith AvPair att res, subst)++-- | 'alignFeat' is a pre-procesing step used to ensure that feature structures+-- have the same set of keys. If a key is missing in one, we copy it to the+-- other with an anonymous value.+--+-- The two feature structures must be sorted for this to work+alignFeat :: Flist GeniVal -> Flist GeniVal -> [(Text,GeniVal,GeniVal)]+alignFeat f1 f2 = alignFeatH f1 f2 []++alignFeatH :: Flist GeniVal -> Flist GeniVal -> [(Text,GeniVal,GeniVal)] -> [(Text,GeniVal,GeniVal)]+alignFeatH [] [] acc = reverse acc+alignFeatH [] (AvPair f v :x) acc = alignFeatH [] x ((f,mkGAnon,v) : acc)+alignFeatH x [] acc = alignFeatH [] x acc+alignFeatH fs1@(AvPair f1 v1:l1) fs2@(AvPair f2 v2:l2) acc =+ case compare f1 f2 of+ EQ -> alignFeatH l1 l2 ((f1, v1, v2) : acc)+ LT -> alignFeatH l1 fs2 ((f1, v1, mkGAnon) : acc)+ GT -> alignFeatH fs1 l2 ((f2, mkGAnon, v2) : acc)++-- --------------------------------------------------------------------+-- Fancy disjunction+-- --------------------------------------------------------------------++crushAvPair :: AvPair [GeniVal] -> Maybe (AvPair GeniVal)+crushAvPair (AvPair a v) = AvPair a `fmap` crushOne v++crushFlist :: Flist [GeniVal] -> Maybe (Flist GeniVal)+crushFlist = mapM crushAvPair++{-!+deriving instance Binary AvPair+deriving instance NFData AvPair+!-}++-- GENERATED START+++instance (Binary a) => Binary (AvPair a) where+ put (AvPair x1 x2)+ = do put x1+ put x2+ get+ = do x1 <- get+ x2 <- get+ return (AvPair x1 x2)++ +instance (NFData a) => NFData (AvPair a) where+ rnf (AvPair x1 x2) = rnf x1 `seq` rnf x2 `seq` ()+-- GENERATED STOP
+ src/NLP/GenI/Flag.hs view
@@ -0,0 +1,146 @@+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE DeriveDataTypeable #-}+-- GenI surface realiser+-- Copyright (C) 2009 Eric Kow+--+-- This module can be treated as public domain++module NLP.GenI.Flag where++-- This module exists purely for the purpose of making it more convenient+-- to modify the flag set in GenI (by eliminating the need to explicitly+-- export the types for individual flags). To add a flag:+--+-- 1. add a type here+-- 2. write the help text in NLP.GenI.Configuration+-- 3. add the getopt stuff and find a section for the flag++import Data.List ( find )+import qualified Data.Set as Set+import Data.Maybe ( catMaybes, fromJust )+import Data.Text ( Text )+import Data.Typeable++import NLP.GenI.FeatureStructure ( Flist )+import NLP.GenI.GeniVal ( GeniVal )+import NLP.GenI.Polarity.Types++-- ----------------------------------------------------------------------+-- configuration stuff+-- this stuff really belongs in NLP.GenI.Configuration but we move it here+-- to avoid an import cycle (sigh)+-- ----------------------------------------------------------------------++data Optimisation = PolOpts+ | AdjOpts+ | Polarised+ | NoConstraints+ deriving (Show,Eq,Typeable)++type Instruction = (FilePath, Maybe [Text])++data BuilderType = SimpleBuilder | SimpleOnePhaseBuilder+ deriving (Eq, Typeable)++data GrammarType = GeniHand -- ^ geni's text format+ | PreCompiled -- ^ built into geni, no parsing needed+ | PreAnchored -- ^ lexical selection already done+ deriving (Show, Eq, Typeable)++instance Show BuilderType where+ show SimpleBuilder = "simple-2p"+ show SimpleOnePhaseBuilder = "simple-1p"++-- ----------------------------------------------------------------------+-- flag core+-- ----------------------------------------------------------------------++{- |+Flags are GenI's internal representation of command line arguments. We+use phantom existential types (?) for representing GenI flags. This+makes it simpler to do things such as ``get the value of the MacrosFlg''+whilst preserving type safety (we always know that MacrosFlg is+associated with String). The alternative would be writing getters and+setters for each flag, and that gets really boring after a while.+-}+data Flag = forall f x . (Eq f, Typeable f, Typeable x) =>+ Flag (x -> f) x deriving (Typeable)++{-+instance Show Flag where+ show (Flag f x) = "Flag " ++ show (f x)+-}++instance Eq Flag where+ (Flag f1 x1) == (Flag f2 x2)+ | (typeOf f1 == typeOf f2) && (typeOf x1 == typeOf x2) =+ (fromJust . cast . f1 $ x1) == (f2 x2)+ | otherwise = False++isFlag :: (Typeable f, Typeable x) => (x -> f) -> Flag -> Bool+isFlag f1 (Flag f2 _) = typeOf f1 == typeOf f2++hasFlag :: (Typeable f, Typeable x) => (x -> f) -> [Flag] -> Bool+hasFlag = any . isFlag++deleteFlag :: (Typeable f, Typeable x) => (x -> f) -> [Flag] -> [Flag]+deleteFlag f = filter (not.(isFlag f))++-- | This only has an effect if the flag is set+modifyFlag :: (Eq f, Typeable f, Typeable x) => (x -> f) -> (x -> x) -> [Flag] -> [Flag]+modifyFlag f m fs =+ case getFlag f fs of+ Nothing -> fs+ Just v -> setFlag f (m v) fs++setFlag :: (Eq f, Typeable f, Typeable x) => (x -> f) -> x -> [Flag] -> [Flag]+setFlag f v fs = (Flag f v) : tl where tl = deleteFlag f fs++getFlag :: (Typeable f, Typeable x) => (x -> f) -> [Flag] -> Maybe x+getFlag f fs = do (Flag _ v) <- find (isFlag f) fs ; cast v++getAllFlags :: (Typeable f, Typeable x) => (x -> f) -> [Flag] -> [x]+getAllFlags f fs = catMaybes [ cast v | flg@(Flag _ v) <- fs, isFlag f flg ]++-- ----------------------------------------------------------------------+-- Below are just the individual flags, which unfortunately have to be+-- defined as separate data types because of our fancy existential+-- data type code.+-- ----------------------------------------------------------------------++newtype BatchDirFlg = BatchDirFlg FilePath deriving (Eq, Typeable)+newtype DisableGuiFlg = DisableGuiFlg () deriving (Eq, Typeable)+newtype DetectPolaritiesFlg = DetectPolaritiesFlg (Set.Set PolarityAttr) deriving (Eq, Typeable)+newtype DumpDerivationFlg = DumpDerivationFlg () deriving (Eq, Typeable)+newtype EarlyDeathFlg = EarlyDeathFlg () deriving (Eq, Typeable)+newtype FromStdinFlg = FromStdinFlg () deriving (Eq, Typeable)+newtype HelpFlg = HelpFlg () deriving (Eq, Typeable)+newtype InstructionsFileFlg = InstructionsFileFlg FilePath deriving (Eq, Typeable)+newtype LexiconFlg = LexiconFlg FilePath deriving (Eq, Typeable)+newtype MacrosFlg = MacrosFlg FilePath deriving (Eq, Typeable)+newtype TracesFlg = TracesFlg FilePath deriving (Eq, Typeable)+newtype MaxStepsFlg = MaxStepsFlg Integer deriving (Eq, Typeable)+newtype MaxResultsFlg = MaxResultsFlg Integer deriving (Eq, Typeable)+newtype MetricsFlg = MetricsFlg [String] deriving (Eq, Typeable)+newtype MorphCmdFlg = MorphCmdFlg String deriving (Eq, Typeable)+newtype MorphInfoFlg = MorphInfoFlg FilePath deriving (Eq, Typeable)+newtype OptimisationsFlg = OptimisationsFlg [Optimisation] deriving (Eq, Typeable)+newtype OutputFileFlg = OutputFileFlg String deriving (Eq, Typeable)+newtype PartialFlg = PartialFlg () deriving (Eq, Typeable)+newtype RankingConstraintsFlg = RankingConstraintsFlg FilePath deriving (Eq, Typeable)+newtype RootFeatureFlg = RootFeatureFlg (Flist GeniVal) deriving (Eq, Typeable)+newtype NoLoadTestSuiteFlg = NoLoadTestSuiteFlg () deriving (Eq, Typeable)+newtype StatsFileFlg = StatsFileFlg FilePath deriving (Eq, Typeable)+newtype TestCaseFlg = TestCaseFlg Text deriving (Eq, Typeable)+newtype TestInstructionsFlg = TestInstructionsFlg [Instruction] deriving (Eq, Typeable)+newtype TestSuiteFlg = TestSuiteFlg FilePath deriving (Eq, Typeable)+newtype TimeoutFlg = TimeoutFlg Int deriving (Eq, Typeable)+newtype VerboseModeFlg = VerboseModeFlg () deriving (Eq, Typeable)+newtype VersionFlg = VersionFlg () deriving (Eq, Typeable)+newtype ViewCmdFlg = ViewCmdFlg String deriving (Eq, Typeable)+newtype BuilderFlg = BuilderFlg BuilderType deriving (Eq, Typeable)+newtype GrammarTypeFlg = GrammarTypeFlg GrammarType deriving (Eq, Typeable)+-- the WeirdFlg exists strictly to please OS X when you launch+-- GenI in an application bundle (double-click)... for some+-- reason it wants to pass an argument to -p+newtype WeirdFlg = WeirdFlg String deriving (Eq, Typeable)
src/NLP/GenI/General.hs view
@@ -20,30 +20,30 @@ -- to replace these functions with versions that are available in the standard -- libraries, or the Haskell platform ones, or on hackage. +{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE DeriveDataTypeable, TypeSynonymInstances #-}+{-# LANGUAGE OverloadedStrings #-} module NLP.GenI.General ( -- * IO ePutStr, ePutStrLn, eFlush,- -- ** Strict readFile- readFile',- lazySlurp,- -- ** Timeouts- withTimeout,- exitTimeout, -- * Strings+ isGeniIdentLetter, dropTillIncluding, trim, toUpperHead, toLowerHead, toAlphaNum,+ quoteString, quoteText,+ clumpBy, -- * Triples+ first3, second3, third3, fst3, snd3, thd3, -- * Lists map',- boundsCheck,+ buckets, isEmptyIntersect, groupByFM,- multiGroupByFM, insertToListMap,- groupAndCount,+ histogram, combinations, mapMaybeM, repList,@@ -57,32 +57,31 @@ -- * Bit vectors BitVector, showBitVector,- -- * Bugs+ -- * Errors, logging and exceptions geniBug,+ prettyException,+ mkLogname, ) where +import Control.Arrow (first)+import Control.Exception (IOException) import Control.Monad (liftM) import Data.Bits (shiftR, (.&.))-import Data.Char (isDigit, isSpace, toUpper, toLower)+import Data.Char (isAlphaNum, isDigit, isSpace, toUpper, toLower) import Data.Function ( on )-import Data.List (foldl', intersect, groupBy, group, sort)+import Data.List (foldl', intersect, inits, intersperse, groupBy, sortBy)+import Data.Typeable ( typeOf, Typeable ) import Data.Tree import System.IO (hPutStrLn, hPutStr, hFlush, stderr)+import System.IO.Error (isUserError, ioeGetErrorString) import qualified Data.Map as Map---- for timeout-import Control.Concurrent-import Control.Exception-import Data.Dynamic(Typeable, typeOf, TyCon, mkTyCon, mkTyConApp, toDyn)-import Data.Unique-import System.Exit(exitWith, ExitCode(ExitFailure))---- for non-lazy IO-import System.IO (openFile, IOMode(ReadMode), hFileSize, hGetBuf)-import System.IO.Unsafe (unsafeInterleaveIO)-import Foreign (mallocForeignPtrBytes, withForeignPtr, ForeignPtr, Ptr, peekElemOff, plusPtr, Word8)-import Data.Char (chr)+import Prelude hiding ( catch )+import Data.Text ( Text )+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import Data.Binary+import Text.JSON -- ---------------------------------------------------------------------- -- IO@@ -102,6 +101,13 @@ -- Strings -- ---------------------------------------------------------------------- +instance Binary Text where+ put = put . T.encodeUtf8+ get = liftM T.decodeUtf8 get++isGeniIdentLetter :: Char -> Bool+isGeniIdentLetter x = isAlphaNum x || x `elem` "_'+-."+ trim :: String -> String trim = reverse . (dropWhile isSpace) . reverse . (dropWhile isSpace) @@ -119,6 +125,44 @@ toLowerHead [] = [] toLowerHead(h:t) = (toLower h):t +quoteString :: String -> String+quoteString xs = "\"" ++ concatMap helper xs ++ "\""+ where+ helper '"' = [ '\\', '\"' ]+ helper '\\' = [ '\\', '\\' ]+ helper x = [ x ]++quoteText :: Text -> Text+quoteText t =+ q `T.append` escape t `T.append` q+ where+ escape = T.replace q escQ . T.replace s escS+ q = "\""+ s = "\\"+ escQ = s `T.append` q+ escS = s `T.append` s++-- | break a list of items into sublists of length < the clump+-- size, taking into consideration that each item in the clump+-- will have a single gap of padding interspersed+--+-- any item whose length is greater than the clump size+-- is put into a clump by itself+--+-- given a length function+-- @clumpBy (length.show) 8 ["hello", "this", "is", "a", "list"]@+clumpBy :: (a -> Int) -> Int -> [a] -> [[a]]+clumpBy f l items = iter [] items+ where+ iter acc [] = reverse acc+ iter acc cs =+ case break toobig (drop 1 $ inits cs) of+ ([],_) -> next 1 -- first too big+ (_,[]) -> iter (cs:acc) [] -- none too big+ (_,(x:_)) -> next (length x - 1)+ where next n = iter (take n cs : acc) (drop n cs)+ toobig x = (sum . intersperse 1 . map f) x > l+ -- ---------------------------------------------------------------------- -- Alphanumeric sort -- ----------------------------------------------------------------------@@ -149,6 +193,15 @@ -- Triples -- ---------------------------------------------------------------------- +first3 :: (a -> a2) -> (a, b, c) -> (a2, b, c)+first3 f (x,y,z) = (f x, y, z)++second3 :: (b -> b2) -> (a, b, c) -> (a, b2, c)+second3 f (x,y,z) = (x, f y, z)++third3 :: (c -> c2) -> (a, b, c) -> (a, b, c2)+third3 f (x,y,z) = (x, y, f z)+ fst3 :: (a,b,c) -> a fst3 (x,_,_) = x @@ -167,11 +220,6 @@ map' _ [] = [] map' f (x:xs) = let a = f x in a `seq` (a:(map' f xs)) --- | Makes sure that index s is in the bounds of list l. --- Surely there must be some more intelligent way to deal with this.-boundsCheck :: Int -> [a] -> Bool-boundsCheck s l = s >= 0 && s < length l- -- | True if the intersection of two lists is empty. isEmptyIntersect :: (Eq a) => [a] -> [a] -> Bool isEmptyIntersect a b = null $ intersect a b@@ -189,15 +237,6 @@ helper acc x = addfn x acc (fn x) in foldl' helper Map.empty list --- | Same as 'groupByFM', except that we let an item appear in--- multiple groups. The fn extracts the property from the item,--- and returns multiple results in the form of a list-multiGroupByFM :: (Ord b) => (a -> [b]) -> [a] -> (Map.Map b [a])-multiGroupByFM fn list = - let addfn x acc key = insertToListMap key x acc- helper acc x = foldl' (addfn x) acc (fn x)- in foldl' helper Map.empty list- {-# INLINE insertToListMap #-} insertToListMap :: (Ord b) => b -> a -> Map.Map b [a] -> Map.Map b [a] insertToListMap k i m =@@ -205,14 +244,15 @@ Nothing -> Map.insert k [i] m Just p -> Map.insert k (i:p) m --- | Convert a list of items into a list of tuples (a,b) where--- a is an item in the list and b is the number of times a--- in occurs in the list.-groupAndCount :: (Eq a, Ord a) => [a] -> [(a, Int)]-groupAndCount xs = - map (\x -> (head x, length x)) grouped- where grouped = (group.sort) xs+histogram :: Ord a => [a] -> Map.Map a Int+histogram xs = Map.fromListWith (+) $ zip xs (repeat 1) +buckets :: Ord b => (a -> b) -> [a] -> [ (b,[a]) ]+buckets f = map (first head . unzip)+ . groupBy ((==) `on` fst)+ . sortBy (compare `on` fst)+ . map (\x -> (f x, x))+ -- Given a list of lists, return all lists such that one item from each sublist is chosen. -- If returns the empty list if there are any empty sublists. combinations :: [[a]] -> [[a]]@@ -256,9 +296,10 @@ -- | Return pairs of (parent, terminal) preTerminals :: Tree a -> [(a,a)]-preTerminals (Node _ []) = []-preTerminals (Node x ks) =- [ (x,y) | (Node y ys) <- ks, null ys ] ++ concatMap preTerminals ks+preTerminals (Node r xs) = concatMap (helper r) xs+ where+ helper p (Node k []) = [ (p,k) ]+ helper _ (Node p ys) = concatMap (helper p) ys -- | 'repNode' @fn filt t@ returns a version of @t@ in which the first -- node which @filt@ matches is transformed using @fn@.@@ -307,7 +348,7 @@ _ -> geniBug "Unexpected result in repNode" -- ------------------------------------------------------------------------- Errors+-- Errors, exceptions and logging -- ---------------------------------------------------------------------- -- | errors specifically in GenI, which is very likely NOT the user's fault.@@ -315,6 +356,15 @@ geniBug s = error $ "Bug in GenI!\n" ++ s ++ "\nPlease file a report on http://trac.haskell.org/GenI/newticket" +-- stolen from Darcs+prettyException :: IOException -> String+prettyException e | isUserError e = ioeGetErrorString e+prettyException e = show e++-- | The module name for an arbitrary data type+mkLogname :: Typeable a => a -> String+mkLogname = reverse . drop 1 . dropWhile (/= '.') . reverse+ . show . typeOf -- ---------------------------------------------------------------------- -- Intervals -- ----------------------------------------------------------------------@@ -349,75 +399,9 @@ showBitVector min_ x = showBitVector (min_ - 1) (shiftR x 1) ++ (show $ x .&. 1) -- ------------------------------------------------------------------------- Strict readfile--- Simon Marlow wrote this code on the Haskell mailing list 2005-08-02.--- -------------------------------------------------------------------------- | Using readFile' can be a good idea if you're dealing with not-so-huge--- files (i.e. where you don't want lazy evaluation), because it ensures--- that the handles are closed. No more ``too many open files''-readFile' :: FilePath -> IO String-readFile' f = do- h <- openFile f ReadMode- s <- hFileSize h- fp <- mallocForeignPtrBytes (fromIntegral s)- len <- withForeignPtr fp $ \buf -> hGetBuf h buf (fromIntegral s)- lazySlurp fp 0 len--buf_size :: Int-buf_size = 4096 :: Int--lazySlurp :: ForeignPtr Word8 -> Int -> Int -> IO String-lazySlurp fp ix len- | fp `seq` False = undefined- | ix >= len = return []- | otherwise = do- cs <- unsafeInterleaveIO (lazySlurp fp (ix + buf_size) len)- ws <- withForeignPtr fp $ \p -> loop (min (len-ix) buf_size - 1)- ((p :: Ptr Word8) `plusPtr` ix) cs- return ws- where- loop :: Int -> Ptr Word8 -> String -> IO String- loop sublen p acc- | sublen `seq` p `seq` False = undefined- | sublen < 0 = return acc- | otherwise = do- w <- peekElemOff p sublen- loop (sublen-1) p (chr (fromIntegral w):acc)---- ------------------------------------------------------------------------- Timeouts+-- JSON -- ---------------------------------------------------------------------- -data TimeOut = TimeOut Unique--timeOutTc :: TyCon-timeOutTc = mkTyCon "TimeOut"--instance Typeable TimeOut where- typeOf _ = mkTyConApp timeOutTc []--withTimeout :: Integer- -> IO a -- ^ action to run upon timing out- -> IO a -- ^ main action to run- -> IO a-withTimeout secs on_timeout action =- do parent <- myThreadId- i <- newUnique- block $ do- timeout <- forkIO (timeout_thread secs parent i)- Control.Exception.catchDyn- ( unblock $ do result <- action- killThread timeout- return result )- ( \ex -> case ex of- TimeOut u | u == i -> unblock on_timeout- _ -> killThread timeout >>= throwDyn ex )- where- timeout_thread secs_ parent i =- do threadDelay $ (fromInteger secs_) * 1000000- throwTo parent (DynException $ toDyn $ TimeOut i)---- | Like 'exitFailure', except that we return with a code that we reserve for timing out-exitTimeout :: IO ()-exitTimeout = exitWith $ ExitFailure 2+instance JSON Text where+ readJSON = fmap T.pack . readJSON+ showJSON = showJSON . T.unpack
− src/NLP/GenI/Geni.lhs
@@ -1,1149 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.--\chapter{Geni}-\label{cha:Geni}--Geni is the interface between the front and backends of the generator. The GUI-and the console interface both talk to this module, and in turn, this module-talks to the input file parsers and the surface realisation engine. This-module also does lexical selection and anchoring because these processes might-involve some messy IO performance tricks.--\begin{code}-module NLP.GenI.Geni (- -- * main interface- ProgState(..), ProgStateRef, emptyProgState,- initGeni,- runGeni, runGeniWithSelector,- GeniResult(..), ResultType(..),- -- * helpers- lemmaSentenceString, prettyResult,- showRealisations, groupAndCount,- getTraces, Selector,- loadEverything, loadLexicon, loadGeniMacros,- loadTestSuite, loadTargetSemStr,- loadRanking, readRanking,- combine,-- -- used by auxiliary tools only- chooseLexCand,- )-where-\end{code}--\ignore{-\begin{code}-import Control.Applicative ((<$>),(<*>))-import Control.Arrow ((&&&))-import Control.Monad.Error-import Control.Monad (unless)--import Data.Binary (Binary, decodeFile)-import Data.Function ( on )-import Data.IORef (IORef, readIORef, modifyIORef)-import Data.List-import Data.List.Split ( wordsBy )-import qualified Data.Map as Map-import Data.Maybe (mapMaybe, fromMaybe, isJust)-import Data.Tree (Tree(Node))-import Data.Typeable (Typeable)--import qualified System.IO.UTF8 as UTF8--import System.IO.Unsafe (unsafePerformIO)-import Text.JSON--- import System.Process ---import NLP.GenI.General(filterTree, repAllNode,- groupAndCount, multiGroupByFM,- geniBug,- repNodeByNode,- fst3,- ePutStr, ePutStrLn, eFlush,- )--import NLP.GenI.Btypes- (Macros, MTtree, ILexEntry, Lexicon,- replace, replaceList,- Sem, SemInput, TestCase(..), sortSem, subsumeSem, params,- GeniVal(GConst), fromGVar, AvPair(..),- GNode(ganchor, gnname, gup, gdown, gaconstr, gtype, gorigin),- GType(Subs, Other),- isemantics, ifamname, iword, iparams, iequations,- iinterface, ifilters,- isempols,- toKeys,- showLexeme, showSem,- pidname, pfamily, pinterface, ptype, psemantics, ptrace,- setAnchor, setLexeme, tree, unifyFeat,- alphaConvert,- )-import NLP.GenI.BtypesBinary ()--import NLP.GenI.Tags (Tags, TagElem, emptyTE,- idname, ttreename,- ttype, tsemantics, ttree, tsempols,- tinterface, ttrace,- setTidnums) --import NLP.GenI.Configuration- ( Params, getFlagP, hasFlagP, hasOpt, Optimisation(NoConstraints)- , MacrosFlg(..), LexiconFlg(..), TestSuiteFlg(..), TestCaseFlg(..)- , MorphInfoFlg(..), MorphCmdFlg(..)- , RankingConstraintsFlg(..)- , PartialFlg(..)- , FromStdinFlg(..), VerboseModeFlg(..)- , NoLoadTestSuiteFlg(..)- , TracesFlg(..)- , grammarType- , GrammarType(..) )--import qualified NLP.GenI.Builder as B--import NLP.GenI.GeniParsers (geniMacros, geniTagElems,- geniLexicon, geniTestSuite,- geniTestSuiteString, geniSemanticInput,- geniMorphInfo,- parseFromFile, runParser, Parser,- )-import NLP.GenI.Morphology-import NLP.GenI.OptimalityTheory-import NLP.GenI.Statistics (Statistics)---- import CkyBuilder --- import SimpleBuilder (simpleBuilder)-\end{code}-}--\begin{code}-myEMPTY :: String-myEMPTY = "MYEMPTY" -\end{code}--% ---------------------------------------------------------------------\section{ProgState}-% ----------------------------------------------------------------------\begin{code}-data ProgState = ST{ -- | the current configuration being processed- pa :: Params,- --- gr :: Macros,- le :: Lexicon,- morphinf :: MorphFn,- ts :: SemInput, - -- | names of test case to run- tcase :: String, - -- | name, original string (for gui), sem- tsuite :: [TestCase],- -- | OT constraints (optional)- ranking :: OtRanking,- -- | simplified traces (optional)- traces :: [String],- -- | any warnings accumulated during realisation- -- (most recent first)- warnings :: [String]- }--type ProgStateRef = IORef ProgState---- | The program state when you start GenI for the very first time-emptyProgState :: Params -> ProgState-emptyProgState args =- ST { pa = args- , gr = []- , le = Map.empty- , morphinf = const Nothing- , ts = ([],[],[])- , tcase = []- , tsuite = []- , traces = []- , ranking = []- , warnings = []- }---- | Log another warning in our internal program state-addWarning :: ProgStateRef -> String -> IO ()-addWarning pstRef s = modifyIORef pstRef $ \p -> p { warnings = s : warnings p }-\end{code}--% ---------------------------------------------------------------------\section{Interface}-\subsection{Loading and parsing}-% ----------------------------------------------------------------------We have one master function that loads all the files GenI is expected to-use. This just calls the sub-loaders below, some of which are exported-for use by the graphical interface. The master function also makes sure-to complain intelligently if some of the required files are missing.--\begin{code}-loadEverything :: ProgStateRef -> IO() -loadEverything pstRef =- do pst <- readIORef pstRef- --- let config = pa pst- isMissing f = not $ hasFlagP f config- -- grammar type- isNotPreanchored = grammarType config /= PreAnchored- isNotPrecompiled = grammarType config /= PreCompiled- useTestSuite = isMissing FromStdinFlg- && isMissing NoLoadTestSuiteFlg- -- display - let errormsg =- concat $ intersperse ", " [ msg | (con, msg) <- errorlst, con ]- errorlst =- [ (isNotPrecompiled && isMissing MacrosFlg,- "a tree file")- , (isNotPreanchored && isMissing LexiconFlg,- "a lexicon file")- , (useTestSuite && isMissing TestSuiteFlg,- "a test suite") ]- unless (null errormsg) $ fail ("Please specify: " ++ errormsg)- -- we only have to read in grammars from the simple format- case grammarType config of - PreAnchored -> return ()- PreCompiled -> return ()- _ -> loadGeniMacros pstRef- -- we don't have to read in the lexicon if it's already pre-anchored- when isNotPreanchored $ loadLexicon pstRef- -- in any case, we have to...- loadMorphInfo pstRef- when useTestSuite $ loadTestSuite pstRef >> return ()- -- the trace filter file- loadTraces pstRef- -- OT ranking- loadRanking pstRef-\end{code}--The file loading functions all work the same way: we load the file,-and try to parse it. If this doesn't work, we just fail in IO, and-GenI dies. If we succeed, we update the program state passed in as-an IORef.--\begin{code}-loadLexicon :: ProgStateRef -> IO ()-loadLexicon pstRef =- do let getSem l = isemantics l- sorter l = l { isemantics = (sortSem . getSem) l }- cleanup = mapBySemKeys isemantics . map sorter- xs <- loadThingOrDie LexiconFlg "lexicon" pstRef- (parseFromFileOrFail geniLexicon)- modifyIORef pstRef (\p -> p { le = cleanup xs })---- | The macros are stored as a hashing function in the monad.-loadGeniMacros :: ProgStateRef -> IO ()-loadGeniMacros pstRef =- do xs <- loadThingOrDie MacrosFlg "trees" pstRef parser- modifyIORef pstRef (\p -> p { gr = xs })- where parser = parseFromFileMaybeBinary geniMacros---- | The results are stored as a lookup function in the monad.-loadMorphInfo :: ProgStateRef -> IO ()-loadMorphInfo pstRef =- do xs <- loadThingOrIgnore MorphInfoFlg "morphological info" pstRef parser- modifyIORef pstRef (\p -> p { morphinf = readMorph xs } )- where parser = parseFromFileOrFail geniMorphInfo--loadTraces :: ProgStateRef -> IO ()-loadTraces pstRef =- do xs <- loadThingOrIgnore TracesFlg "traces" pstRef- (\f -> lines `fmap` readFile f)- modifyIORef pstRef (\p -> p {traces = xs})--loadRanking :: ProgStateRef -> IO ()-loadRanking pstRef =- do config <- pa `fmap` readIORef pstRef- let verbose = hasFlagP VerboseModeFlg config- case getFlagP RankingConstraintsFlg config of- Nothing -> return ()- Just f -> do r <- readRanking verbose f- modifyIORef pstRef (\p -> p { ranking = r })--readRanking :: Bool -- ^ verbose- -> FilePath -> IO OtRanking-readRanking verbose f =- do when verbose $ do- ePutStr $ unwords [ "Loading OT constraints", f ++ "... " ]- eFlush- mr <- (resultToEither . decode) `fmap` UTF8.readFile f -- utf-8?- when verbose $ ePutStr "done"- either fail return mr-\end{code}--\subsubsection{Target semantics}--Reading in the target semantics (or test suite) is a little more-complicated. It follows the same general schema as above, except-that we parse the file twice: once for our internal representation,-and once to get a string representation of each test case. The-string representation is for the graphical interface; it avoids us-figuring out how to pretty-print things because we can assume the-user will format it the way s/he wants.--\begin{code}--- | Stores the results in the tcase and tsuite fields-loadTestSuite :: ProgStateRef -> IO [TestCase]-loadTestSuite pstRef = do- config <- pa `fmap` readIORef pstRef- let parser f = do- sem <- parseFromFileOrFail geniTestSuite f- mStrs <- parseFromFileOrFail geniTestSuiteString f- return $ zip sem mStrs- updater s x =- x { tsuite = s- , tcase = fromMaybe "" $ getFlagP TestCaseFlg config}- cleanup (tc,str) =- tc { tcSem = (sortSem sm, sort sr, lc)- , tcSemString = str }- where (sm, sr, lc) = tcSem tc- xs <- map cleanup `fmap` loadThingOrDie TestSuiteFlg "test suite" pstRef parser- modifyIORef pstRef (updater xs)- return xs-\end{code}--Sometimes, the target semantics does not come from a file, but from-the graphical interface, so we also provide the ability to parse an-arbitrary string as the semantics.--\begin{code}--- | Updates program state the same way as 'loadTestSuite'-loadTargetSemStr :: ProgStateRef -> String -> IO ()-loadTargetSemStr pstRef str = - do parseSem- where- parseSem = do- let sem = runParser geniSemanticInput () "" str- case sem of- Left err -> fail (show err)- Right sr -> modifyIORef pstRef (\x -> x{ts = smooth sr})- smooth (s,r,l) = (sortSem s, sort r, l)-\end{code}--\subsubsection{Helpers for loading files}--\begin{code}-loadThingOrIgnore, loadThingOrDie :: forall f a . (Eq f, Show f, Typeable f)- => (FilePath -> f) -- ^ flag- -> String- -> ProgStateRef- -> (FilePath -> IO [a])- -> IO [a]---- | Load the file if the relevant option is set, otherwise ignore-loadThingOrIgnore flag description pstRef parser =- do config <- pa `fmap` readIORef pstRef- case getFlagP flag config of- Nothing -> return []- Just f -> loadThing f description pstRef parser---- | Load the file if the relevant option is set, otherwise complain and die-loadThingOrDie flag description pstRef parser =- do config <- pa `fmap` readIORef pstRef- case getFlagP flag config of- Nothing -> fail $ "Please specify a " ++ description ++ "!"- Just f -> loadThing f description pstRef parser--loadThing :: FilePath -- ^ file to load- -> String -- ^ description- -> ProgStateRef- -> (FilePath -> IO [a]) -- ^ parsing cmd- -> IO [a]-loadThing filename description pstRef parser =- do config <- pa `fmap` readIORef pstRef- let verbose = hasFlagP VerboseModeFlg config- when verbose $ do- ePutStr $ unwords [ "Loading", description, filename ++ "... " ]- eFlush- theTs <- parser filename- when verbose $ ePutStr $ (show $ length theTs) ++ " entries\n"- return theTs--parseFromFileOrFail :: Parser a -> FilePath -> IO a-parseFromFileOrFail p f = parseFromFile p f >>= either (fail.show) (return)--parseFromFileMaybeBinary :: Binary a- => Parser a- -> FilePath- -> IO a-parseFromFileMaybeBinary p f =- if (".genib" `isSuffixOf` f)- then decodeFile f- else parseFromFileOrFail p f-\end{code}--% ---------------------------------------------------------------------\subsection{Surface realisation - entry point}-% ----------------------------------------------------------------------This is your basic entry point. You call this if the only thing you want to do-is run the surface realiser.--\begin{enumerate}-\item It initialises the realiser (lexical selection, among other things),- via \fnref{initGeni}-\item It runs the builder (the surface realisation engine proper)-\item It unpacks the builder results -\item It finalises the results (morphological generation)-\end{enumerate}--\begin{code}-data GeniResult = GeniResult- { grLemmaSentence :: B.LemmaPlusSentence- , grRealisations :: [String]- , grDerivation :: B.Derivation- , grLexSelection :: [ GeniLexSel ]- , grRanking :: Int- , grViolations :: [ OtViolation ]- , grResultType :: ResultType- } deriving (Ord, Eq)--data GeniLexSel = GeniLexSel- { nlTree :: String- , nlTrace :: [String]- } deriving (Ord, Eq)--data ResultType = CompleteResult | PartialResult deriving (Ord, Eq)---- | Returns a list of sentences, a set of Statistics, and the generator state.--- The generator state is mostly useful for debugging via the graphical interface.--- Note that we assumes that you have already loaded in your grammar and--- parsed your input semantics.-runGeni :: ProgStateRef -> B.Builder st it Params -> IO ([GeniResult], Statistics, st)-runGeni pstRef builder = runGeniWithSelector pstRef defaultSelector builder--runGeniWithSelector :: ProgStateRef -> Selector -> B.Builder st it Params -> IO ([GeniResult], Statistics, st)-runGeniWithSelector pstRef selector builder =- do pst <- readIORef pstRef- let config = pa pst- run = B.run builder- unpack = B.unpack builder- -- step 1: lexical selection- initStuff <- initGeniWithSelector pstRef selector- -- step 2: chart generation- let (finalSt, stats) = run initStuff config- -- step 3: unpacking- let uninflected = unpack finalSt- tryPartial = null uninflected && hasFlagP PartialFlg config- rawResults = if tryPartial then B.partial builder finalSt else uninflected- resultTy = if tryPartial then PartialResult else CompleteResult- -- step 4: post-processing- results <- finaliseResults pstRef resultTy rawResults- return (results, stats, finalSt)-\end{code}--% ---------------------------------------------------------------------\subsection{Surface realisation - sub steps}-% ----------------------------------------------------------------------Below are the initial and final steps of \fnreflite{runGeni}. These functions-are seperated out so that they may be individually called from the graphical-debugger. The middle steps (running and unpacking the builder) depend on your-builder implementation.--\begin{code}--- | 'initGeni' performs lexical selection and strips the input semantics of--- any morpohological literals-initGeni :: ProgStateRef -> IO (B.Input)-initGeni pstRef = initGeniWithSelector pstRef defaultSelector--initGeniWithSelector :: ProgStateRef -> Selector -> IO (B.Input)-initGeniWithSelector pstRef lexSelector =- do -- disable constraints if the NoConstraintsFlg anti-optimisation is active- modifyIORef pstRef- (\p -> if hasOpt NoConstraints (pa p)- then p { ts = (fst3 (ts p),[],[]) }- else p)- -- lexical selection- (cand, lexonly) <- lexSelector pstRef- pst <- readIORef pstRef- -- strip morphological predicates- let (tsem,tres,lc) = ts pst- tsem2 = stripMorphSem (morphinf pst) tsem- --- let initStuff = B.Input - { B.inSemInput = (tsem2, tres, lc)- , B.inLex = lexonly - , B.inCands = map (\c -> (c,-1)) cand- }- return initStuff ---- | 'finaliseResults' does any post-processing steps that we want to integrate--- into mainline GenI. So far, this consists of morphological realisation and--- OT ranking-finaliseResults :: ProgStateRef -> ResultType -> [B.Output] -> IO [GeniResult]-finaliseResults pstRef ty os =- do pst <- readIORef pstRef- -- morph TODO: make this a bit safer- mss <- case getFlagP MorphCmdFlg (pa pst) of- Nothing -> return $ map sansMorph sentences- Just cmd -> map snd `fmap` inflectSentencesUsingCmd cmd sentences- -- OT ranking- let unranked = zipWith (sansRanking pst) os mss- rank = rankResults (getTraces pst) grDerivation (ranking pst)- return . map addRanking . rank $ unranked- where- sentences = map fst os- sansRanking pst (l,d) rs =- GeniResult { grLemmaSentence = l- , grRealisations = rs- , grDerivation = d- , grLexSelection = map (\x -> GeniLexSel x (getTraces pst x)) (B.lexicalSelection d)- , grRanking = -1- , grViolations = []- , grResultType = ty- }- addRanking (i,res,vs) = res { grViolations = vs, grRanking = i }-\end{code}--% ---------------------------------------------------------------------\subsection{Displaying results}-% ----------------------------------------------------------------------\begin{code}--- | Show the sentences produced by the generator, in a relatively compact form-showRealisations :: [String] -> String-showRealisations sentences =- let sentencesGrouped = map (\ (s,c) -> s ++ countStr c) g- where g = groupAndCount sentences - countStr c = if c > 1 then " (" ++ show c ++ " instances)"- else ""- in if null sentences- then "(none)"- else unlines sentencesGrouped---- | No morphology! Pretend the lemma string is a sentence-lemmaSentenceString :: GeniResult -> String-lemmaSentenceString = unwords . map lpLemma . grLemmaSentence--prettyResult :: ProgState -> GeniResult -> String-prettyResult pst nr =- concat . intersperse "\n" . map showOne . grRealisations $ nr- where- showOne str = show theRanking ++ ". " ++ str ++ "\n" ++ violations- violations = prettyViolations tracesFn verbose (grViolations nr)- theRanking = grRanking nr- verbose = hasFlagP VerboseModeFlg (pa pst)- tracesFn = getTraces pst---- | 'getTraces' is most likely useful for grammars produced by a--- metagrammar system. Given a tree name, we retrieve the ``trace''--- information from the grammar for all trees that have this name. We--- assume the tree name was constructed by GenI; see the source code for--- details.-getTraces :: ProgState -> String -> [String]-getTraces pst tname =- filt $ concat [ ptrace t | t <- gr pst, pidname t == readPidname tname ]- where- filt = case traces pst of- [] -> id- theTs -> filter (`elem` theTs)---- | We assume the name was constructed by 'combineName'-readPidname :: String -> String-readPidname n =- case wordsBy (== ':') n of- (_:_:p:_) -> p- _ -> geniBug "readPidname or combineName are broken"-\end{code}--% ---------------------------------------------------------------------\section{Lexical selection}-\label{sec:candidate_selection} \label{sec:lexical_selecetion} \label{par:lexSelection}-% ----------------------------------------------------------------------\paragraph{runLexSelection} \label{fn:runLexSelection} determines which-candidates trees which will be used to generate the current target semantics. -In addition to the anchored candidate trees, we also return the lexical items -themselves. This list of lexical items is useful for debugging a grammar; -it lets us know if GenI managed to lexically select something, but did not -succeed in anchoring it.--\begin{code}-runLexSelection :: ProgStateRef -> IO ([TagElem], [ILexEntry])-runLexSelection pstRef =- do pst <- readIORef pstRef- -- select lexical items first- let (tsem,_,litConstrs) = ts pst- lexicon = le pst- lexCand = chooseLexCand lexicon tsem- config = pa pst- verbose = hasFlagP VerboseModeFlg config- -- then anchor these lexical items to trees- let grammar = gr pst- combineWithGr l =- do let (lexCombineErrors, res) = combineList grammar l- familyMembers = [ p | p <- grammar, pfamily p == ifamname l ]- mapM_ (addWarning pstRef . showErr) $ compressLexCombineErrors- $ lexCombineErrors- -- snippets of error message- let lexeme = showLexeme.iword $ l- _outOfFamily n = show n ++ "/" ++ (show $ length familyMembers)- ++ " instances of " ++ lexeme ++ ":" ++ ifamname l- -- print out missing coanchors list- case concatMap (missingCoanchors l) familyMembers of- [] -> return ()- cs -> mapM_ showWarning . group . sort $ cs- where showWarning [] = geniBug "silly error in Geni.runLexSelection"- showWarning xs@(x0:_) = addWarning pstRef $ "Missing co-anchor '" ++ x0 ++ "'" ++ " in " ++ _outOfFamily (length xs) ++ "."- -- print out enrichment errors-{-- unless (null enrichEs) $ do- let numDiscards = length enrichEs- badEnrichments = [ av | av <- iequations l, hasMatch av ]- hasMatch (a,_) = any (== parsePathEq a) errLocs- errLocs = map eeLocation enrichEs- ePutStrLn $ "Warning: Discarded "- ++ _outOfFamily numDiscards- ++ "\n due to enrichment failure with "- ++ "[" ++ showPairs badEnrichments ++ "]."- mapM (ePutStrLn.show) otherEs--}-- -- FIXMENOW when (not.null $ errs) $ ePutStrLn (unlines errs)- return res- cand <- case grammarType config of- PreAnchored -> readPreAnchored pst- _ -> concat `liftM` mapM combineWithGr lexCand- -- attach any morphological information to the candidates- let considerMorph = attachMorph (morphinf pst) tsem- -- filter out candidates which do not fulfill the trace constraints- let matchesLc t = all (`elem` myTrace) constrs- where constrs = concat [ cs | (l,cs) <- litConstrs, l `elem` mySem ]- mySem = tsemantics t- myTrace = ttrace t- considerLc = filter matchesLc- -- filter out candidates whose semantics has bonus stuff which does- -- not occur in the input semantics- let considerCoherency = filter (all (`elem` tsem) . tsemantics)- considerHasSem = filter (not . null . tsemantics)- --- let candFinal = setTidnums . considerCoherency . considerHasSem- . considerLc . considerMorph $ cand- indent x = ' ' : x- unlinesIndentAnd :: (x -> String) -> [x] -> String- unlinesIndentAnd f = unlines . map (indent . f)- when verbose $- do ePutStrLn $ "Lexical items selected:\n" ++ (unlinesIndentAnd (showLexeme.iword) lexCand)- ePutStrLn $ "Trees anchored (family) :\n" ++ (unlinesIndentAnd idname candFinal)- -- lexical selection failures- let missedSem = tsem \\ (nub $ concatMap tsemantics candFinal)- hasTree l = isJust $ find (\t -> tsemantics t == lsem) cand- where lsem = isemantics l- missedLex = filter (not.hasTree) lexCand- unless (null missedSem) $ addWarning pstRef $ "no lexical selection for " ++ showSem missedSem- unless (null missedLex) $ forM_ missedLex $ \l -> addWarning pstRef $- "'" ++ showLex l ++ "' was lexically selected, but not anchored to any trees"- return (candFinal, lexCand)- where showLex l = (showLexeme $ iword l) ++ "-" ++ (ifamname l)- showErr (c, e) = show e ++ " (" ++ show c ++ " times)"--compressLexCombineErrors :: [LexCombineError] -> [(Int, LexCombineError)]-compressLexCombineErrors = map (length &&& head) . groupBy h- where- h (EnrichError m1 l1 _) (EnrichError m2 l2 _) = pfamily m1 == pfamily m2 &&- iword l1 == iword l2- h _ _ = False---- | Select and returns the set of entries from the lexicon whose semantics--- subsumes the input semantics.-chooseLexCand :: Lexicon -> Sem -> [ILexEntry]-chooseLexCand slex tsem = - let keys = toKeys tsem- -- we choose candidates that match keys- lookuplex t = Map.findWithDefault [] t slex- cand = concatMap lookuplex $ myEMPTY : keys- -- and refine the selection... - cand2 = chooseCandI tsem cand- -- treat synonyms as a single lexical entry- -- FIXME: disabled see mergeSynonyms for explanation- -- cand3 = mergeSynonyms cand2- in cand2-\end{code}--With a helper function, we refine the candidate selection by-instatiating the semantics, at the same time filtering those which-do not stay within the target semantics, and finally eliminating -the duplicates.--\begin{code}-chooseCandI :: Sem -> [ILexEntry] -> [ILexEntry]-chooseCandI tsem cand =- let replaceLex i (sem,sub) = - (replace sub i) { isemantics = sem }- --- helper :: ILexEntry -> [ILexEntry]- helper l = if null sem then [l]- else map (replaceLex l) psubsem- where psubsem = subsumeSem tsem sem- sem = isemantics l- --- in nub $ concatMap helper cand -\end{code}--A semantic key is a semantic literal boiled down to predicate plus arity-(see section \ref{btypes_semantics}).---\begin{code}--- | 'mapBySemKeys' @xs fn@ organises items (@xs@) by their semantic key--- (retrieved by @fn@). An item may have multiple keys.---- This is used to organise the lexicon by its semantics.-mapBySemKeys :: (a -> Sem) -> [a] -> Map.Map String [a]-mapBySemKeys semfn xs = - let gfn t = if (null s) then [myEMPTY] else toKeys s - where s = semfn t- in multiGroupByFM gfn xs-\end{code}--\fnlabel{mergeSynonyms} is a factorisation technique that uses-atomic disjunction to merge all synonyms into a single lexical-entry. Two lexical entries are considered synonyms if their-semantics match and they point to the same tree families.--FIXME: 2006-10-11 - note that this is no longer being used,-because it breaks the case where two lexical entries differ-only by their use of path equations. Perhaps it's worthwhile-just to add a check that the path equations match exactly.--\begin{code}-{--mergeSynonyms :: [ILexEntry] -> [ILexEntry]-mergeSynonyms lexEntry =- let mergeFn l1 l2 = l1 { iword = (iword l1) ++ (iword l2) }- keyFn l = (ifamname l, isemantics l) - synMap = foldr helper Map.empty lexEntry- where helper x acc = Map.insertWith mergeFn (keyFn x) x acc - in Map.elems synMap--}-\end{code}--% ---------------------------------------------------------------------\subsection{Basic anchoring}-\label{sec:combine_macros}-% ----------------------------------------------------------------------This section of the code helps you to combined a selected lexical item with-a macro or a list of macros. This is a process that can go fail for any-number of reasons, so we try to record the possible failures for book-keeping.--\begin{code}-data LexCombineError =- BoringError String- | EnrichError { eeMacro :: MTtree- , eeLexEntry :: ILexEntry- , eeLocation :: PathEqLhs }- | OtherError MTtree ILexEntry String--instance Error LexCombineError where- noMsg = strMsg "error combining items"- strMsg s = BoringError s--instance Show LexCombineError where- show (BoringError s) = s- show (OtherError t l s) = s ++ " on " ++ pfamily t ++ " (" ++ (showLexeme $ iword l) ++ ")"- show (EnrichError t l _) = show (OtherError t l "enrichment error")-\end{code}--The first step in lexical selection is to collect all the features and-parameters that we want to combine.--\begin{code}--- | 'combine' @macros lex@ creates the 'Tags' repository combining lexical--- entries and un-anchored trees from the grammar. It also unifies the--- parameters used to specialize un-anchored trees and propagates additional--- features given in the 'ILexEntry'.-combine :: Macros -> Lexicon -> Tags-combine gram lexicon =- let helper li = mapEither (combineOne li) macs- where tn = ifamname li- macs = [ t | t <- gram, pfamily t == tn ]- in Map.map (\e -> concatMap helper e) lexicon --mapEither :: (a -> Either l r) -> [a] -> [r]-mapEither fn = mapMaybe (\x -> either (const Nothing) Just $ fn x)-\end{code}--\begin{code}--- | Given a lexical item, looks up the tree families for that item, and--- anchor the item to the trees.-combineList :: Macros -> ILexEntry- -> ([LexCombineError],[TagElem]) -- ^ any warnings, plus the results-combineList gram lexitem =- case [ t | t <- gram, pfamily t == tn ] of- [] -> ([BoringError $ "Family " ++ tn ++ " not found in Macros"],[])- macs -> unzipEither $ map (combineOne lexitem) macs- where tn = ifamname lexitem--unzipEither :: (Error e, Show b) => [Either e b] -> ([e], [b])-unzipEither es = helper ([],[]) es where- helper accs [] = accs- helper (eAcc, rAcc) (Left e : next) = helper (e:eAcc,rAcc) next- helper (eAcc, rAcc) (Right r : next) = helper (eAcc,r:rAcc) next-\end{code}--\begin{code}--- | Combine a single tree with its lexical item to form a bonafide TagElem.--- This process can fail, however, because of filtering or enrichement-combineOne :: ILexEntry -> MTtree -> Either LexCombineError TagElem-combineOne lexRaw eRaw = -- Maybe monad- -- trace ("\n" ++ (show wt)) $- do let l1 = alphaConvert "-l" lexRaw- e1 = alphaConvert "-t" eRaw- (l,e) <- unifyParamsWithWarning (l1,e1)- >>= unifyInterfaceUsing iinterface- >>= unifyInterfaceUsing ifilters -- filtering- >>= enrichWithWarning -- enrichment- let name = concat $ intersperse ":" $ filter (not.null)- [ head (iword l) , pfamily e , pidname e ]- return $ emptyTE- { idname = name- , ttreename = pfamily e- , ttype = ptype e- , ttree = setOrigin name . setLemAnchors . setAnchor (iword l) $ tree e- , tsemantics =- sortSem $ case psemantics e of- Nothing -> isemantics l- Just s -> s- , tsempols = isempols l- , tinterface = pinterface e- , ttrace = ptrace e- }- where- unifyParamsWithWarning (l,t) =- -- trace ("unify params " ++ wt) $- let lp = iparams l- tp = map fromGVar $ params t- psubst = zip tp lp- in if (length lp) /= (length tp)- then Left $ OtherError t l $ "Parameter length mismatch"- else Right $ (replaceList psubst l, replaceList psubst t)- --- unifyInterfaceUsing ifn (l,e) =- -- trace ("unify interface" ++ wt) $- case unifyFeat (ifn l) (pinterface e) of- Nothing -> Left $ OtherError e l $ "Interface unification error"- Just (int2, fsubst) -> Right $ (replace fsubst l, e2)- where e2 = (replace fsubst e) { pinterface = int2 }- --- enrichWithWarning (l,e) =- -- trace ("enrich" ++ wt) $- do e2 <- enrich l e- return (l,e2)-\end{code}--\subsubsection{Enrichment}--Enrichment is a process which adds features to either the interface, an-explicitly named node or the co-anchor of a lexically selected tree. The-enrichement information comes from the lexicon in the form of a path equations-which specify-\begin{enumerate}-\item the location-\item top or bottom-\item the attribute-\item what value to associate with it-\end{enumerate}--The conventions taken by GenI for path equations are:--\begin{tabular}{|l|p{8cm}|}-\hline-\verb!interface.foo=bar! &-\fs{foo=bar} is unified into the interface (not the tree) \\-\hline-\verb!anchor.bot.foo=bar! &-\fs{foo=bar} is unified into the bottom feature of the node-which is marked anchor. \\-\hline-\verb!toto.top.foo=bar! &-\fs{foo=bar} is unified into the top feature of node named toto \\-\hline-\verb!toto.bot.foo=bar! &-\fs{foo=bar} is unified into the bot feature of node named toto \\-\hline-\verb!anchor.foo=bar! &-same as \verb!anchor.bot.foo=bar! \\-\hline-\verb!anc.whatever...! &-same as \verb!anchor.whatever...! \\-\hline-\verb!top.foo=bar! &-same as \verb!anchor.top.foo=bar! \\-\hline-\verb!bot.foo=bar! &-same as \verb!anchor.bot.foo=bar! \\-\hline-\verb!foo=bar! &-same as \verb!anchor.bot.foo=bar! \\-\hline-\verb!toto.foo=bar! &-same as \verb!toto.top.foo=bar! (creates a warning) \\-\hline-\end{tabular}--\begin{code}--- | (node, top, att) (node is Nothing if anchor)-type PathEqLhs = (String, Bool, String)-type PathEqPair = (PathEqLhs, GeniVal)--enrich :: ILexEntry -> MTtree -> Either LexCombineError MTtree-enrich l t =- do -- separate into interface/anchor/named- let (intE, namedE) = lexEquations l- -- enrich the interface and everything else- t2 <- foldM enrichInterface t intE- -- enrich everything else- foldM (enrichBy l) t2 namedE- where- toAvPair ((_,_,a),v) = AvPair a v- enrichInterface tx en =- do (i2, isubs) <- unifyFeat [toAvPair en] (pinterface tx)- `catchError` (\_ -> throwError $ ifaceEnrichErr en)- return $ (replace isubs tx) { pinterface = i2 }- ifaceEnrichErr (loc,_) = EnrichError- { eeMacro = t- , eeLexEntry = l- , eeLocation = loc }--enrichBy :: ILexEntry -- ^ lexeme (for debugging info)- -> MTtree- -> (PathEqLhs, GeniVal) -- ^ enrichment eq- -> Either LexCombineError MTtree-enrichBy lexEntry t (eqLhs, eqVal) =- case seekCoanchor eqName t of- Nothing -> return t -- to be robust, we accept if the node isn't there- Just a ->- do let tfeat = (if eqTop then gup else gdown) a- (newfeat, sub) <- unifyFeat [AvPair eqAtt eqVal] tfeat- `catchError` (\_ -> throwError enrichErr)- let newnode = if eqTop then a {gup = newfeat}- else a {gdown = newfeat}- return $ fixNode newnode $ replace sub t- where- (eqName, eqTop, eqAtt) = eqLhs- fixNode n mt = mt { tree = repNodeByNode (matchNodeName eqName) n (tree mt) }- enrichErr = EnrichError { eeMacro = t- , eeLexEntry = lexEntry- , eeLocation = eqLhs }--pathEqName :: PathEqPair -> String-pathEqName = fst3.fst--missingCoanchors :: ILexEntry -> MTtree -> [String]-missingCoanchors lexEntry t =- -- list monad- do eq <- nubBy ((==) `on` pathEqName) $ snd $ lexEquations lexEntry- let name = pathEqName eq- case seekCoanchor name t of- Nothing -> [name]- Just _ -> []---- | Split a lex entry's path equations into interface enrichement equations--- or (co-)anchor modifiers-lexEquations :: ILexEntry -> ([PathEqPair], [PathEqPair])-lexEquations =- partition (nameIs "interface") . map parseAv . iequations- where- parseAv (AvPair a v) =- case parsePathEq a of- Left (err,peq) -> unsafePerformIO $ do putStrLn err- return (peq,v)- Right peq -> (peq, v)- nameIs n x = pathEqName x == n--seekCoanchor :: String -> MTtree -> Maybe GNode-seekCoanchor eqName t =- case filterTree (matchNodeName eqName) (tree t) of- [a] -> Just a- [] -> Nothing- _ -> geniBug $ "Tree with multiple matches in enrichBy. " ++- "\nTree: " ++ pidname t ++ "\nFamily: " ++ pfamily t ++- "\nMatching on: " ++ eqName--matchNodeName :: String -> GNode -> Bool-matchNodeName "anchor" = ganchor-matchNodeName n = (== n) . gnname---- | Parse a path equation using the GenI conventions--- This always succeeds, but can return @Just warning@--- if anything anomalous comes up-parsePathEq :: String -> Either (String,PathEqLhs) (PathEqLhs)-parsePathEq e =- case wordsBy (== '.') e of- (n:"top":r) -> Right (n, True, rejoin r)- (n:"bot":r) -> Right (n, False, rejoin r)- ("top":r) -> Right ("anchor", True, rejoin r)- ("bot":r) -> Right ("anchor", False, rejoin r)- ("anc":r) -> parsePathEq $ rejoin $ "anchor":r- ("anchor":r) -> Right ("anchor", False, rejoin r)- ("interface":r) -> Right ("interface", False, rejoin r)- (n:r) -> Left (err, (n, True, rejoin r))- where err = "Warning: Interpreting path equation " ++ e ++- " as applying to top of " ++ n ++ "."- _ -> Left (err, ("", True, e))- where err = "Warning: could not interpret path equation " ++ e- where- rejoin = concat . intersperse "."-\end{code}--\subsubsection{Lemanchor mechanism}--One problem in building reversible grammars is the treatment of co-anchors.-In the French language, for example, we have some structures like-\natlang{C'est Jean qui regarde Marie}-\natlang{It is John who looks at Mary}--One might be tempted to hard code the ce (it) and the être (is) into the tree-for regarder (look at), something like \texttt{s(ce, être, n$\downarrow$, qui,-v(regarder), n$\downarrow$)}. Indeed, this would work just fine for-generation, but not for parsing. When you parse, you would encounter inflected-forms for these items for example \natlang{c'} for \natlang{ce} or-\natlang{sont} or \natlang{est} for \natlang{être}. Hard-coding the \natlang{ce}-into such trees would break parsing.--To work around this, we propose a mechanism to have our co-anchors and parsing-too. Co-anchors that are susceptible to morphological variation should be-\begin{itemize}-\item marked in a substitution site (this is to keep parsers happy)-\item have a feature \texttt{bot.lemanchor:foo} where foo is the- coanchor you want-\end{itemize}--GenI will convert these into non-substitution sites with a lexical item-leaf node.--\begin{code}-setLemAnchors :: Tree GNode -> Tree GNode-setLemAnchors t =- repAllNode fn filt t- where- filt (Node a []) = gtype a == Subs && (isJust. lemAnchor) a- filt _ = False- fn (Node x k) = setLexeme (lemAnchorMaybeFake x) $- Node (x { gtype = Other, gaconstr = False }) k- --- lemAnchorMaybeFake :: GNode -> [String]- lemAnchorMaybeFake n =- case lemAnchor n of- Nothing -> ["ERR_UNSET_LEMMANCHOR"]- Just l -> l- lemAnchor :: GNode -> Maybe [String]- lemAnchor n =- case [ v | AvPair a v <- gdown n, a == _lemanchor ] of- [GConst l] -> Just l- _ -> Nothing--_lemanchor :: String-_lemanchor = "lemanchor"-\end{code}--\subsubsection{Node origins}--After lexical selection, we label each tree node with its origin, most-likely the name and id of its elementary tree. This is useful for-building derivation trees--\begin{code}-setOrigin :: String -> Tree GNode -> Tree GNode-setOrigin t = fmap (\g -> g { gorigin = t })-\end{code}--% ---------------------------------------------------------------------\subsection{Pre-selection and pre-anchoring}-\label{sec:pre-anchor}-% ----------------------------------------------------------------------For testing purposes, we can perform lexical selection ahead of time and store-it somewhere else.--\begin{code}--- | Only used for instances of GenI where the grammar is compiled--- directly into GenI.-type Selector = ProgStateRef -> IO ([TagElem],[ILexEntry])--defaultSelector :: Selector-defaultSelector = runLexSelection-\end{code}--For debugging purposes, it is often useful to perform lexical selection and-surface realisation separately. Pre-anchored mode allows the user to just-pass the lexical selection in as a file of anchored trees associated with a-semantics.--\begin{code}-readPreAnchored :: ProgState -> IO [TagElem]-readPreAnchored pst =- case getFlagP MacrosFlg (pa pst) of- Nothing -> fail "No macros file specified (preanchored mode)"- Just file -> parseFromFileOrFail geniTagElems file-\end{code}--% ---------------------------------------------------------------------% Boring utility code-% ----------------------------------------------------------------------\ignore{-\begin{code}-instance JSON GeniResult where- readJSON j =- do jo <- fromJSObject `fmap` readJSON j- let field x = maybe (fail $ "Could not find: " ++ x) readJSON- $ lookup x jo- GeniResult <$> field "raw"- <*> field "realisations"- <*> field "derivation"- <*> field "lexical-selection"- <*> field "ranking"- <*> field "violations"- <*> field "result-type"- showJSON nr =- JSObject . toJSObject $ [ ("raw", showJSON $ grLemmaSentence nr)- , ("realisations", showJSONs $ grRealisations nr)- , ("derivation", showJSONs $ grDerivation nr)- , ("lexical-selection", showJSONs $ grLexSelection nr)- , ("ranking", showJSON $ grRanking nr)- , ("violations", showJSONs $ grViolations nr)- , ("result-type", showJSON $ grResultType nr)- ]--instance JSON ResultType where- readJSON j =- do js <- fromJSString `fmap` readJSON j- case js of- "partial" -> return PartialResult- "complete" -> return CompleteResult- ty -> fail $ "unknown result type: " ++ ty- showJSON CompleteResult = JSString $ toJSString "complete"- showJSON PartialResult = JSString $ toJSString "partial"--instance JSON GeniLexSel where- readJSON j =- do jo <- fromJSObject `fmap` readJSON j- let field x = maybe (fail $ "Could not find: " ++ x) readJSON- $ lookup x jo- GeniLexSel <$> field "lex-item"- <*> field "trace"- showJSON x =- JSObject . toJSObject $ [ ("lex-item", showJSON $ nlTree x)- , ("trace", showJSONs $ nlTrace x)- ]-\end{code}-}-
− src/NLP/GenI/GeniParsers.lhs
@@ -1,919 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.--\chapter{File formats}-\label{cha:formats}-\label{cha:GeniParsers}--This chapter is a description of the file formats used by \geni. We'll be-using EBNFs to describe the format below. Here are some rules and types of-rules we leave out, and prefer to describe informally:--\begin{verbatim}-<alpha-numeric>-<string-literal> (stuff between quotes)-<opt-whatever> (systematically... "" | <whatever>)-<keyword-whatever> (systematically.. "whatever" ":")-\end{verbatim}--\ignore{-\begin{code}-module NLP.GenI.GeniParsers (- -- * Test suites- geniTestSuite, geniSemanticInput, geniTestSuiteString,- geniDerivations,- toSemInputString,- -- * Trees- geniMacros, geniTagElems,- -- * Lexicon and morph- geniLexicon, geniMorphInfo,- -- * Basics- geniFeats, geniPolarities, geniSemantics, geniValue, geniWords,- -- * Helpers- geniWord, geniLanguageDef, tillEof,- --- parseFromFile, -- UTF-8 version- module Text.ParserCombinators.Parsec-) where--import NLP.GenI.General ((!+!), Interval, ival)-import NLP.GenI.Btypes-import NLP.GenI.Tags (TagElem(..), emptyTE, setTidnums)-import NLP.GenI.GeniShow (GeniShow(geniShow))-import NLP.GenI.PolarityTypes--import Control.Monad (liftM, when)-import Data.List (sort)-import qualified Data.Map as Map-import qualified Data.Tree as T-import Text.ParserCombinators.Parsec hiding (parseFromFile)-import Text.ParserCombinators.Parsec.Language (emptyDef)-import Text.ParserCombinators.Parsec.Token (TokenParser,- LanguageDef(..), makeTokenParser)-import qualified Text.ParserCombinators.Parsec.Token as P-import qualified System.IO.UTF8 as UTF8--\end{code}-}--\section{General notes}--\subsection{Comments}--Any \geni format file can include comments. Comments start \verb!%!.-There is also the option of using \verb'/* */' for embedded comments.--\subsection{Reserved words}--The following are reserved words. You should not use them as variable names.-NB: the reserved words are indicated below between quotes; eg. ``semantics''.-You can ignore C pre-processor noise such as \verb!#define SEMANTICS!--\begin{includecodeinmanual}-\begin{code}--- reserved words-#define SEMANTICS "semantics"-#define SENTENCE "sentence"-#define OUTPUT "output"-#define TRACE "trace"-#define ANCHOR "anchor"-#define SUBST "subst"-#define FOOT "foot"-#define LEX "lex"-#define TYPE "type"-#define ACONSTR_NOADJ "aconstr:noadj"-#define INITIAL "initial"-#define AUXILIARY "auxiliary"-#define IDXCONSTRAINTS "idxconstraints"-#define BEGIN "begin"-#define END "end"-\end{code}-\end{includecodeinmanual}--\subsection{Lexer}--For reference, we include the Parsec LanguageDef that we use to implement-the \geni format.--\begin{includecodeinmanual}-\begin{code}-geniLanguageDef :: LanguageDef ()-geniLanguageDef = emptyDef- { commentLine = "%"- , commentStart = "/*"- , commentEnd = "*/"- , opLetter = oneOf ""- , reservedOpNames = [""]- , reservedNames =- [ SEMANTICS , SENTENCE, OUTPUT, IDXCONSTRAINTS, TRACE- , ANCHOR , SUBST , FOOT , LEX , TYPE , ACONSTR_NOADJ- , INITIAL , AUXILIARY- , BEGIN , END ]- , identLetter = identStuff- , identStart = identStuff- }- where identStuff = alphaNum <|> oneOf "_'+-."-\end{code}-\end{includecodeinmanual}--\section{The basics}--\subsection{Variables and constants}--Below are some examples of \geni variables and constants. Note that we support-atomic disjunction of constants, as in \verb!Foo|bar|baz!, but not variables.--\begin{center}-\begin{tabular}{ll}-anonymous variable & \verb!?_! or \verb!_! \\-variables & \verb!Foo!, \verb!?X! or \verb!?x! \\-constants & \verb!Foo!, \verb!foo!, \verb!X!, \verb!x! or \verb!Foo|bar! \\-\end{tabular}-\end{center}--Here is an EBNF for GenI variables and constants--\begin{SaveVerbatim}{KoweyTmp}-<value> ::= <variable> | <anonymous-variable> | <constant-disj>-<variable> ::= "?" <identifier>-<anonymous> ::= "?_" | "_"-<constant-disj> ::= <constant> (| <constant>)*-<constant> ::= <identifier>-<identifier> ::= <alphanumeric> | "+" | "-" | "_"-\end{SaveVerbatim}-\begin{center}-\fbox{\BUseVerbatim{KoweyTmp}}-\end{center}--\begin{code}-geniValue :: Parser GeniVal-geniValue = ((try $ anonymous) <?> "_ or ?_")- <|> (constants <?> "a constant or atomic disjunction")- <|> (variable <?> "a variable")- where- question = "?"- --- constants :: Parser GeniVal- constants =- do c <- sepBy1 (looseIdentifier <|> stringLiteral) (symbol "|")- return (GConst c)- variable :: Parser GeniVal- variable =- do symbol question- v <- identifier- return (GVar v)- anonymous :: Parser GeniVal- anonymous =- do optional $ symbol question- symbol "_"- return GAnon-\end{code}--\subsection{Feature structures}--In addition to variables and constants, \geni also makes heavy use of flat-feature structures. They take the form \verb![foo:bar ping:?Pong]!, or more-formally,--\begin{SaveVerbatim}{KoweyTmp}-<feature-structure> ::= "[" <atttribute-value-pair>* "]"-<attribute-value-pair> ::= <identifier-or-reserved> ":" <value>-<identifier-or-reserved> ::= <identifier> | <reserved>-\end{SaveVerbatim}-\begin{center}-\fbox{\BUseVerbatim{KoweyTmp}}-\end{center}--\begin{code}-geniFeats :: Parser Flist-geniFeats = option [] $ squares $ many geniAttVal--geniAttVal :: Parser AvPair-geniAttVal = do- att <- identifierR <?> "an attribute"; colon- val <- geniValue <?> "a GenI value"- return $ AvPair att val-\end{code}--\subsection{Semantics}-\label{sec:geni-semantics}--A \jargon{semantics} is basically a set of literals. Semantics are used in-to provide \geni input (section \ref{sec:geni-input-semantics}) and in the-definition of lexical entries (section \ref{sec:geni-lexicon}).--Notice that this is a flat semantic representation! No literals within-literals, please. A literal can take one of two forms:-\begin{verbatim}- handle:predicate(arguments)- predicate(arguments)-\end{verbatim}--The arguments are space-delimited. Not providing a handle is-equivalent to providing an anonymous one.--\begin{SaveVerbatim}{KoweyTmp}-<semantics> ::= <keyword-semantics> "[" <literal>* "]"-<literal> ::= <identifier> "(" <value>* ")"-\end{SaveVerbatim}-\begin{center}-\fbox{\BUseVerbatim{KoweyTmp}}-\end{center}--\begin{code}-geniSemantics :: Parser Sem-geniSemantics =- do sem <- many (geniLiteral <?> "a literal")- return (sortSem sem)--geniLiteral :: Parser Pred-geniLiteral =- do handle <- option GAnon handleParser <?> "a handle"- predicate <- geniValue <?> "a predicate"- pars <- parens (many geniValue) <?> "some parameters"- --- return (handle, predicate, pars)- where handleParser =- try $ do { h <- geniValue ; char ':' ; return h }-\end{code}--\section{Semantic inputs and test suites}-\label{sec:geni-input-semantics}--\subsection{Semantic input}--The semantic input can either be provided directly in the graphical interface-or as part of a test suite.--The format for semantic inputs is actually a bit richer than the core-definition in section \ref{sec:geni-semantics}, but I have not yet written the-documentation for it.--\textbf{TODO}: The semantics may contain literal based constraints as described-in section \ref{sec:fixme}. These constraints are just a space-delimited list-of String. When returning the results, we separate them out from the semantics-proper so that they can be treated separately. Index constraints are-represented as feature structures.--\begin{code}-geniSemanticInput :: Parser (Sem,Flist,[LitConstr])-geniSemanticInput =- do keywordSemantics- (sem,litC) <- liftM unzip $ squares $ many literalAndConstraint- idxC <- option [] geniIdxConstraints- --- let sem2 = createHandles sem- semlitC2 = [ (s,c) | (s,c) <- zip sem2 litC, (not.null) c ]- return (createHandles sem, idxC, semlitC2)- where- -- set all anonymous handles to some unique value- -- this is to simplify checking if a result is- -- semantically complete- createHandles :: Sem -> Sem- createHandles = zipWith setHandle ([1..] :: [Int])- --- setHandle i (h, pred_, par) =- let h2 = if h /= GAnon then h- else GConst ["genihandle" ++ (show i)]- in (h2, pred_, par)- --- literalAndConstraint :: Parser (Pred, [String])- literalAndConstraint =- do l <- geniLiteral- t <- option [] $ squares $ many identifier- return (l,t)---- | The original string representation of the semantics (for gui)-geniSemanticInputString :: Parser String-geniSemanticInputString =- do keywordSemantics- s <- squaresString- whiteSpace- optional geniIdxConstraints- return s--geniIdxConstraints :: Parser Flist-geniIdxConstraints = keyword IDXCONSTRAINTS >> geniFeats--squaresString :: Parser String-squaresString =- do char '['- s <- liftM concat $ many $ (many1 $ noneOf "[]") <|> squaresString- char ']'- return $ "[" ++ s ++ "]"---- the output end of things--- displaying preformatted semantic input--data SemInputString = SemInputString String Flist--instance GeniShow SemInputString where- geniShow (SemInputString semStr idxC) =- SEMANTICS ++ ":" ++ semStr ++ (if null idxC then "" else r)- where r = "\n" ++ IDXCONSTRAINTS ++ ": " ++ showFlist idxC--toSemInputString :: SemInput -> String -> SemInputString-toSemInputString (_,lc,_) s = SemInputString s lc-\end{code}--\subsection{Test suite}--\geni accepts an entire test suite of semantic inputs that you can choose from.-The test suite entries can be named. In fact, it is probably a good idea to do-so, because the names are often shorter than the expected output, and easier to-read than the semantics. Note the expected output isn't used by \geni itself,-but external tools that ``test'' \geni.--\begin{SaveVerbatim}{KoweyTmp}-<test-suite> ::= <test-suite-entry>*-<test-suite-entry> ::= <opt-identifier> <semantics> <expected-output>*-<expected-output> ::= <opt-keyword-sentence> "[" <identifier>* "]"-\end{SaveVerbatim}-\begin{center}-\fbox{\BUseVerbatim{KoweyTmp}}-\end{center}--\begin{code}-geniTestSuite :: Parser [TestCase]-geniTestSuite =- tillEof (many geniTestCase)---- | Just the String representations of the semantics--- in the test suite-geniTestSuiteString :: Parser [String]-geniTestSuiteString =- tillEof (many geniTestCaseString)---- | This is only used by the script genimakesuite-geniDerivations :: Parser [TestCaseOutput]-geniDerivations = tillEof $ many geniOutput--geniTestCase :: Parser TestCase-geniTestCase =- do name <- option "" (identifier <?> "a test case name")- seminput <- geniSemanticInput- sentences <- many geniSentence- outputs <- many geniOutput- return $ TestCase name "" seminput sentences outputs---- note that the keyword is NOT optional-type TestCaseOutput = (String, Map.Map (String,String) [String])-geniOutput :: Parser TestCaseOutput-geniOutput =- do ws <- keyword OUTPUT >> (squares geniWords)- ds <- Map.fromList `fmap` many geniTraces- return (ws, ds)--geniTraces :: Parser ((String,String), [String])-geniTraces =- do keyword TRACE- squares $ do- k1 <- withWhite geniWord- k2 <- withWhite geniWord- whiteSpace >> char '!' >> whiteSpace- traces <- sepEndBy1 geniWord whiteSpace- return ((k1,k2), traces)--withWhite :: Parser a -> Parser a-withWhite p = p >>= (\a -> whiteSpace >> return a)--geniSentence :: Parser String-geniSentence = optional (keyword SENTENCE) >> squares geniWords--geniWords :: Parser String-geniWords =- unwords `fmap` (sepEndBy1 geniWord whiteSpace <?> "a sentence")--geniWord :: Parser String-geniWord = many1 (noneOf "[]\v\f\t\r\n ")---- | The original string representation of a test case semantics--- (for gui)-geniTestCaseString :: Parser String-geniTestCaseString =- do option "" (identifier <?> "a test case name")- s <- geniSemanticInputString- many geniSentence- many geniOutput- return s-\end{code}--\section{Lexicon}-\label{sec:geni-lexicon}--The lexicon associates semantic entries with lemmas and trees.--\subsection{Lexicon examples}--There are two ways to write the lexicon. We show the old (deprecated)-way first because most of the examples are still written in this style.--\paragraph{Example 1 (deprecated)}--\begin{verbatim}-le clitic (?I)-semantics:[]--le Det (?I)-semantics:[def(?I)]--livre nC (?I)-semantics:[book(?I)]--persuader vArity3 (?E ?X ?Y ?Z)-semantics:[?E:convince(?X ?Y ?Z)]--persuader v vArity3controlObj-semantics:[?E:convince(?X ?Y ?Z)]-\end{verbatim}--\paragraph{Example 2 (preferred)}--\begin{verbatim}-detester n0Vn1-equations:[theta1:agent theta2:patient arg1:?X arg2:?Y evt:?L]-filters:[family:n0Vn1]-semantics:[?E:hate(?L) ?E:agent(?L ?X) ?E:patient(?L ?Y)]-\end{verbatim}--\subsection{Notes about lexicons}--\begin{itemize}-\item The semantics associated with a lexicali item may have more than one literal-\begin{verbatim}-cher adj (?E ?X ?Y)-semantics:[?E:cost(?X ?Y) ?E:high(?Y)]-\end{verbatim}--\item A lemma may have more than one distinct semantics-\begin{verbatim}-bank n (?X)-semantics:[bank(?X)]--bank v (?E ?X ?D)-semantics:[?E:lean(?X,?D)]-\end{verbatim}--\item A semantics may be realised by more than one lexical entry (e.g. synonynms)-\begin{verbatim}-livre nC (?I)-semantics:[book(?I)]--bouquin nC (?I)-semantics:[book(?I)]-\end{verbatim}-\end{itemize}--\subsection{Lexicon EBNF}--\begin{SaveVerbatim}{KoweyTmp}-<lexicon> ::= <lexicon-entry>*-<lexicon-entry> ::= <lexicon-header> <opt-filters> <semantics>-<lexicon-header> ::= <lemma> <family> <parameters>- | <lemma> <family> <keyword-equations> <feature-structure>-<parameters> ::= "(" <value>* <opt-interface> ")"-<interface> ::= "!" <attribute-value-pairs>*-<filters> ::= <keyword-filter> <feature-structure>-\end{SaveVerbatim}-\begin{center}-\fbox{\BUseVerbatim{KoweyTmp}}-\end{center}--\begin{code}-geniLexicon :: Parser [ILexEntry]-geniLexicon = tillEof $ many1 geniLexicalEntry--geniLexicalEntry :: Parser ILexEntry-geniLexicalEntry =- do lemma <- (looseIdentifier <|> stringLiteral) <?> "a lemma"- family <- identifier <?> "a tree family"- (pars, interface) <- option ([],[]) $ parens paramsParser- equations <- option [] $ do keyword "equations"- geniFeats <?> "path equations"- filters <- option [] $ do keyword "filters"- geniFeats- keywordSemantics- (sem,pols) <- squares geniLexSemantics- --- return emptyLE { iword = [lemma]- , ifamname = family- , iparams = pars- , iinterface = sortFlist interface- , iequations = equations- , ifilters = filters- , isemantics = sem- , isempols = pols }- where- paramsParser :: Parser ([GeniVal], Flist)- paramsParser = do- pars <- many geniValue <?> "some parameters"- interface <- option [] $ do symbol "!"- many geniAttVal- return (pars, interface)--geniLexSemantics :: Parser (Sem, [[Int]])-geniLexSemantics =- do litpols <- many (geniLexLiteral <?> "a literal")- return $ unzip litpols--geniLexLiteral :: Parser (Pred, [Int])-geniLexLiteral =- do (handle, hpol) <- option (GAnon,0) (handleParser <?> "a handle")- predicate <- geniValue <?> "a predicate"- paramsPols <- parens (many geniPolValue) <?> "some parameters"- --- let (pars, pols) = unzip paramsPols- literal = (handle, predicate, pars)- return (literal, hpol:pols)- where handleParser =- try $ do { h <- geniPolValue; colon; return h }--geniPolValue :: Parser (GeniVal, Int)-geniPolValue =- do p <- geniPolarity- v <- geniValue- return (v,p)-\end{code}--\section{Tree schemata}--The tree schemata file (for historical reasons, this is also called the macros-file) contains a set of unlexicalised trees organised into families. Such-``macros'' consist of a--\begin{enumerate}-\item a family name and (optionally) a macro name-\item a list of parameters-\item ''initial'' or ''auxiliary''-\item a tree.-\end{enumerate}--\subsection{Trees}--\jargon{Trees} are recursively defined structure of form \verb!node{tree*}!-For example, in the table below, the structure on the left should produce the-tree on the right:--\begin{SaveVerbatim}{KoweyTmp}-n1{- n2- n3{- n4- n5- }- n6-}-\end{SaveVerbatim}-\begin{tabular}{ll}-\BUseVerbatim{KoweyTmp} & \includegraphics[scale=0.50]{images/tree-format-example.png} \\-\end{tabular}--\subsection{Nodes}--\jargon{Nodes} consist of-\begin{enumerate}-\item a name-\item a type (optional)-\item either a lexeme, or top and bottom feature structures. Here are examples of the five possible kinds of nodes:-\end{enumerate}--\noindent-Here are some examples of nodes-\begin{verbatim}- n1 [cat:n idx:?I]![cat:n idx:?I] % basic- n3 type:subst [cat:n idx:?Y]![cat:n idx:?Y] % subst- n4 type:foot [cat:n idx:?Y]![cat:n idx:?Y] % foot- n5 type:lex "de" % coanchor- n2 anchor % anchor- n5 aconstr:noadj % node with a null-adjunction constraint (other than subst or foot)-\end{verbatim}--\subsection{Example}--\begin{verbatim}-adj:post(?I) auxiliary-n0[cat:n idx:?I det:_]![cat:n idx:?I det:minus ]-{- n1 type:foot [cat:n idx:?I det:minus]![cat:n idx:?I det:minus]- n2[cat:a]![]- {- n3 anchor- }-}--adj:pre(?I) auxiliary-n0[cat:n idx:?I det:_ qu:_]![cat:n idx:?I det:minus ]-{- n1[cat:a]![]- {- n2 anchor- }- n3 type:foot [cat:n idx:?I det:minus]![cat:n idx:?I det:minus]-}--vArity2:n0vn1(?E ?X ?Y) initial-n1[cat:p]![]-{- n2 type:subst [cat:n idx:?X det:plus]![cat:n idx:?X]- n3[cat:v idx:?E]![]- {- n4 anchor- }- n5 type:subst [cat:n idx:?Y det:plus]![cat:n idx:?Y]-}-\end{verbatim}--\subsection{EBNF}--\begin{SaveVerbatim}{KoweyTmp}-<macros> ::= <macro>*-<macro> ::= <family-name> <opt-macro-name> <parameters> <tree-type> <tree>- <opt-semantics> <opt-trace>--<parameters> ::= "(" <value>* <opt-interface> ")"-<interface> ::= ! <attribute-value-pair>*-<macro-name> ::= <identifier>-<tree-type> ::= "initial" | "auxiliary"-<trace> ::= <keyword-trace> "[" <identifier>* "]"--<tree> ::= <node> | <node> "{" <tree>* "}"-<node> ::= <node-name> <opt-node-type> <node-payload>-<node-name> ::= <identifier>-<node-type> ::= <keyword-type> <core-node-type> | "anchor"-<core-node-type> ::= "foot" | "subst" | "lex"-<node-payload> ::= <string-literal> | <feature-structure> "!" <feature-structure>-\end{SaveVerbatim}-\begin{center}-\fbox{\BUseVerbatim{KoweyTmp}}-\end{center}--\begin{code}-geniMacros :: Parser [MTtree]-geniMacros = tillEof $ many geniTreeDef--initType, auxType :: Parser Ptype-initType = do { reserved INITIAL ; return Initial }-auxType = do { reserved AUXILIARY ; return Auxiliar }--geniTreeDef :: Parser MTtree-geniTreeDef =- do sourcePos <- getPosition- family <- identifier- tname <- option "" $ do { colon; identifier }- (pars,iface) <- geniParams- theTtype <- (initType <|> auxType)- theTree <- geniTree- -- sanity checks?- let treeFail x =- do setPosition sourcePos -- FIXME does not do what I expect- fail $ "In tree " ++ family ++ ":" ++ tname ++ " " ++ show sourcePos ++ ": " ++ x- let theNodes = T.flatten theTree- numFeet = length [ x | x <- theNodes, gtype x == Foot ]- numAnchors = length [ x | x <- theNodes, ganchor x ]- when (not $ any ganchor theNodes) $- treeFail "At least one node in an LTAG tree must be an anchor"- when (numAnchors > 1) $- treeFail "There can be no more than 1 anchor node in a tree"- when (numFeet > 1) $- treeFail "There can be no more than 1 foot node in a tree"- when (theTtype == Initial && numFeet > 0) $- treeFail "Initial trees may not have foot nodes"- --- psem <- option Nothing $ do { keywordSemantics; liftM Just (squares geniSemantics) }- ptrc <- option [] $ do { keyword TRACE; squares (many identifier) }- --- return TT{ params = pars- , pfamily = family- , pidname = tname- , pinterface = sortFlist iface- , ptype = theTtype- , tree = theTree- , ptrace = ptrc- , psemantics = psem- }--geniTree :: Parser (T.Tree GNode)-geniTree =- do node <- geniNode- kids <- option [] (braces $ many geniTree)- <?> "child nodes"- -- sanity checks- let noKidsAllowed t c = when (c node && (not.null $ kids)) $- fail $ t ++ " nodes may *not* have any children"- noKidsAllowed "Anchor" $ ganchor- noKidsAllowed "Substitution" $ (== Subs) . gtype- noKidsAllowed "Foot" $ (== Foot) . gtype- --- return (T.Node node kids)--geniNode :: Parser GNode-geniNode =- do name <- identifier- nodeType <- option "" ( (keyword TYPE >> typeParser)- <|>- reserved ANCHOR)- lex_ <- if nodeType == LEX- then (sepBy (stringLiteral<|>identifier) (symbol "|") <?> "some lexemes")- else return []- constr <- case nodeType of- "" -> adjConstraintParser- ANCHOR -> adjConstraintParser- _ -> return True- (top_,bot_) <- -- features only obligatory for non-lex nodes- if nodeType == LEX- then option ([],[]) $ try topbotParser- else topbotParser- --- let top = sort top_- bot = sort bot_- nodeType2 = case nodeType of- ANCHOR -> Lex- LEX -> Lex- FOOT -> Foot- SUBST -> Subs- "" -> Other- other -> error ("unknown node type: " ++ other)- return $ GN { gnname = name, gtype = nodeType2- , gup = top, gdown = bot- , glexeme = lex_- , ganchor = (nodeType == ANCHOR)- , gaconstr = constr- , gorigin = "" }- where- typeParser = choice $ map (try.symbol) [ ANCHOR, FOOT, SUBST, LEX ]- adjConstraintParser = option False $ reserved ACONSTR_NOADJ >> return True- topbotParser =- do top <- geniFeats <?> "top features"- symbol "!"- bot <- geniFeats <?> "bot features"- return (top,bot)---- | This makes it possible to read anchored trees, which may be--- useful for debugging purposes.------ FIXME: note that this is very rudimentary; we do not set id numbers,--- parse polarities. You'll have to call--- some of our helper functions if you want that functionality.-geniTagElems :: Parser [TagElem]-geniTagElems = tillEof $ setTidnums `fmap` many geniTagElem--geniTagElem :: Parser TagElem-geniTagElem =- do family <- identifier- tname <- option "" $ do { colon; identifier }- iface <- (snd `liftM` geniParams) <|> geniFeats- theType <- initType <|> auxType- theTree <- geniTree- sem <- do { keywordSemantics; squares geniSemantics }- --- return $ emptyTE { idname = tname- , ttreename = family- , tinterface = iface- , ttype = theType- , ttree = theTree- , tsemantics = sem }---- | 'geniParams' recognises a list of parameters optionally followed by a--- bang (\verb$!$) and a list of attribute-value pairs. This whole thing is--- to wrapped in the parens.------ TODO: deprecate-geniParams :: Parser ([GeniVal], Flist)-geniParams = parens $ do- pars <- many geniValue <?> "some parameters"- interface <- option [] $ do { symbol "!"; many geniAttVal }- return (pars, interface)-\end{code}--\section{Morphology}--A morphinfo file associates predicates with morphological feature structures.-Each morphological entry consists of a predicate followed by a feature-structuer. For more information, see chapter \ref{cha:Morphology}.-(\textbf{TODO}: describe format)--\begin{code}-geniMorphInfo :: Parser [(String,Flist)]-geniMorphInfo = tillEof $ many morphEntry--morphEntry :: Parser (String,Flist)-morphEntry =- do pred_ <- identifier- feats <- geniFeats- return (pred_, feats)-\end{code}--% ======================================================================-% everything else-% ======================================================================--\begin{code}--- ------------------------------------------------------------------------- polarities--- -----------------------------------------------------------------------geniPolarities :: Parser (Map.Map PolarityKey Interval)-geniPolarities = tillEof $ toMap `fmap` many pol- where- toMap = Map.fromListWith (!+!)- pol = do p <- geniPolarity- i <- identifier- return (PolarityKey i,ival p)---- | 'geniPolarity' associates a numerical value to a polarity symbol,--- that is, '+' or '-'.-geniPolarity :: Parser Int-geniPolarity = option 0 (plus <|> minus)- where- plus = do { char '+'; return 1 }- minus = do { char '-'; return (-1) }---- ------------------------------------------------------------------------- keyword--- ------------------------------------------------------------------------{-# INLINE keyword #-}-keyword :: String -> Parser String-keyword k =- do let helper = try $ do { reserved k; colon; return k }- helper <?> k ++ ":"--{-# INLINE keywordSemantics #-}-keywordSemantics :: Parser String-keywordSemantics = keyword SEMANTICS---- ------------------------------------------------------------------------- language def helpers--- ------------------------------------------------------------------------lexer :: TokenParser ()-lexer = makeTokenParser geniLanguageDef--whiteSpace :: CharParser () ()-whiteSpace = P.whiteSpace lexer--looseIdentifier, identifier, stringLiteral, colon :: CharParser () String-identifier = P.identifier lexer---- stolen from Parsec code (ident)--- | Like 'identifier' but allows for reserved words too-looseIdentifier =- do { i <- ident ; whiteSpace; return i }- where- ident =- do { c <- identStart geniLanguageDef- ; cs <- many (identLetter geniLanguageDef)- ; return (c:cs) } <?> "identifier"--stringLiteral = P.stringLiteral lexer-colon = P.colon lexer--squares, braces, parens :: CharParser () a -> CharParser () a-squares = P.squares lexer-braces = P.braces lexer-parens = P.parens lexer--reserved, symbol :: String -> CharParser () String-reserved s = P.reserved lexer s >> return s-symbol = P.symbol lexer---- ------------------------------------------------------------------------- parsec helpers--- -------------------------------------------------------------------------- | identifier, permitting reserved words too-identifierR :: CharParser () String-identifierR- = do { c <- P.identStart geniLanguageDef- ; cs <- many (P.identLetter geniLanguageDef)- ; return (c:cs)- }- <?> "identifier or reserved word"--tillEof :: Parser a -> Parser a-tillEof p =- do whiteSpace- r <- p- eof- return r---- stolen from Parsec and adapted to use UTF-8 input-parseFromFile :: Parser a -> SourceName -> IO (Either ParseError a)-parseFromFile p fname- = do{ input <- UTF8.readFile fname- ; return (parse p fname input)- }-\end{code}
src/NLP/GenI/GeniShow.hs view
@@ -15,157 +15,55 @@ -- along with this program; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -{--We need to be able to dump some of GenI's data structures into a simple-text format we call GeniHand.--There are at least two uses for this, one is that it allows us to-interrupt the debugging process, dump everything to file, muck around-with the trees and then pick up where we left off.--The other use is to make large grammars faster to load. We don't actually do-this anymore, mind you, but it's nice to have the option. The idea is to take-a massive XML grammar, parse it to a set of TagElems and then write these back-in the lighter syntax. It's not that XML is inherently less efficient to parse-than the handwritten syntax, just that writing an efficient parser for XML-based format is more annoying, so I stuck with HaXml to make my life easy.-Unfortunately, HaXml seems to have some kind of space leak.--}- -- This module provides specialised functions for visualising tree data.+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances, TypeSynonymInstances #-}+{-# LANGUAGE OverloadedStrings #-} module NLP.GenI.GeniShow where +import Data.Text ( Text ) import Data.Tree-import Data.List(intersperse, isPrefixOf)-import qualified Data.Map as Map--import NLP.GenI.Tags- ( TagElem, idname,- tsemantics, ttree, tinterface, ttype, ttreename,- )-import NLP.GenI.Btypes (GeniVal(GConst), AvPair(..), Ptype(..),- Ttree(params, pidname, pfamily, pinterface, ptype, tree, psemantics, ptrace),- GNode(..), GType(..),- SemInput, Pred,- TestCase(..),- )+import qualified Data.Text as T+import NLP.GenI.Pretty +-- | GenI format; should round-trip with 'NLP.GenI.Parser' by rights+--+-- Minimal definition, either one of 'geniShow' or 'geniShowText' class GeniShow a where- geniShow :: a -> String--instance GeniShow Ptype where- geniShow Initial = "initial"- geniShow Auxiliar = "auxiliary"- geniShow _ = ""--instance GeniShow AvPair where- geniShow (AvPair a v) = a ++ ":" ++ geniShow v--instance GeniShow GeniVal where- geniShow (GConst xs) = concat $ intersperse "|" xs- geniShow x = show x--instance GeniShow Pred where- geniShow (h, p, l) =- showh ++ geniShow p ++ "(" ++ unwords (map geniShow l) ++ ")"- where- hideh (GConst [x]) = "genihandle" `isPrefixOf` x- hideh _ = False- showh = if hideh h then "" else geniShow h ++ ":"--instance GeniShow GNode where- geniShow x =- let gaconstrstr = case (gaconstr x, gtype x) of- (True, Other) -> "aconstr:noadj"- _ -> ""- gtypestr n = case (gtype n) of- Subs -> "type:subst"- Foot -> "type:foot"- Lex -> if ganchor n && (null.glexeme) n- then "type:anchor" else "type:lex"- _ -> ""- glexstr n =- if null ls then ""- else concat $ intersperse "|" $ map quote ls- where quote s = "\"" ++ s ++ "\""- ls = glexeme n- tbFeats n = (geniShow $ gup n) ++ "!" ++ (geniShow $ gdown n)- in unwords $ filter (not.null) $ [ gnname x, gaconstrstr, gtypestr x, glexstr x, tbFeats x ]+ geniShow :: a -> String+ geniShow = T.unpack . geniShowText -instance (GeniShow a) => GeniShow [a] where- geniShow = squares . unwords . (map geniShow)+ geniShowText :: a -> Text+ geniShowText = T.pack . geniShow instance (GeniShow a) => GeniShow (Tree a) where- geniShow t =- let treestr i (Node a l) =- spaces i ++ geniShow a ++- case (l,i) of- ([], 0) -> "{}"- ([], _) -> ""- (_, _) -> "{\n" ++ (unlines $ map next l) ++ spaces i ++ "}"- where next = treestr (i+1)- --- spaces i = take i $ repeat ' '- in treestr 0 t--instance GeniShow TagElem where- geniShow te =- "\n% ------------------------- " ++ idname te- ++ "\n" ++ (ttreename te) ++ ":" ++ (idname te)- ++ " " ++ (geniShow.tinterface $ te)- ++ " " ++ (geniShow.ttype $ te)- ++ "\n" ++ (geniShow.ttree $ te)- ++ "\n" ++ geniShowKeyword "semantics" "" ++ (geniShow.tsemantics $ te)--instance (GeniShow a) => GeniShow (Ttree a) where- geniShow tt =- "\n% ------------------------- " ++ pidname tt- ++ "\n" ++ (pfamily tt) ++ ":" ++ (pidname tt)- ++ " " ++ (parens $ (unwords $ map geniShow $ params tt)- ++ " ! "- ++ (unwords $ map geniShow $ pinterface tt))- ++ " " ++ (geniShow.ptype $ tt)- ++ "\n" ++ (geniShow.tree $ tt)- ++ (case psemantics tt of- Nothing -> ""- Just psem -> "\n" ++ geniShowKeyword "semantics" (geniShow psem))- ++ "\n" ++ geniShowKeyword "trace" (squares.unwords.ptrace $ tt)+ geniShowText = geniShowTree 0 -instance GeniShow TestCase where- geniShow (TestCase { tcName = name- , tcExpected = sentences- , tcOutputs = outputs- , tcSemString = semStr- , tcSem = sem }) =- unlines $ [ name, semS ]- ++ map (geniShowKeyword "sentence" . squares) sentences- ++ (concat.prettify.map outStuff $ outputs)+geniShowTree :: GeniShow a => Int -> Tree a -> Text+geniShowTree i (Node a l) =+ spaces <> geniShowText a <> rest where- semS = if null semStr then geniShowSemInput sem "" else semStr- prettify = if all (Map.null . snd) outputs then id else map ("":)- gshowTrace ((k1,k2),ts) =- geniShowKeyword "trace" . squares . showString (k1 ++ " " ++ k2 ++ " ! " ++ unwords ts) $ ""- outStuff (o,ds) =- [ geniShowKeyword "output" . squares $ o ]- ++ (map gshowTrace $ Map.toList ds)+ rest = case (l,i) of+ ([], 0) -> "{}"+ ([], _) -> ""+ (_, _) -> "{\n" <> T.unlines (map next l)+ <> spaces+ <> "}"+ next = geniShowTree (i+1)+ spaces = T.pack (replicate i ' ') +{-+geniShowSmallList :: GeniShow a => [a] -> String+geniShowSmallList = squares . unwords . (map geniShow) -parens, squares :: String -> String-parens s = "(" ++ s ++ ")"-squares s = "[" ++ s ++ "]"+instance GeniShow [Literal] where+ geniShow = geniShowSmallList -geniShowKeyword :: String -> ShowS-geniShowKeyword k = showString k . showChar ':'+instance GeniShow (AvPair v) => GeniShow [AvPair v] where+ geniShow = geniShowSmallList -geniShowSemInput :: SemInput -> ShowS-geniShowSemInput (sem,icons,lcons) =- let withConstraints lit =- case concat [ cs | (p,cs) <- lcons, p == lit ] of- [] -> geniShow lit- cs -> geniShow lit ++ (squares . unwords $ cs)- semStuff = geniShowKeyword "semantics" . squares- . (showString . unwords . map withConstraints $ sem)- idxStuff = geniShowKeyword "idxconstraints"- . (showString . geniShow $ icons) . squares- in semStuff . (if null icons then id else showChar '\n' . idxStuff)+-}++geniKeyword :: Text -> Text -> Text+geniKeyword k t = k `T.append` ":" `T.append` t
src/NLP/GenI/GeniVal.hs view
@@ -16,294 +16,31 @@ -- along with this program; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -{-# LANGUAGE OverlappingInstances, FlexibleInstances, DeriveDataTypeable #-}-module NLP.GenI.GeniVal where---- import Debug.Trace -- for test stuff-import Control.Arrow (first, (***))-import Control.Monad (liftM)-import Data.List-import Data.Maybe (fromMaybe, isJust)-import Data.Generics (Data)-import Data.Typeable (Typeable)-import qualified Data.Map as Map--import Test.HUnit-import Test.QuickCheck hiding (collect)-import Test.Framework-import Test.Framework.Providers.HUnit-import Test.Framework.Providers.QuickCheck--import Data.Generics.PlateDirect--import Control.Parallel.Strategies--import NLP.GenI.General (geniBug)--data GeniVal = GConst [String] -- ^ atomic disjunction - constant x | y | z- | GVar String -- ^ variable- | GAnon -- ^ anonymous- deriving (Eq,Ord, Data, Typeable)--instance Uniplate GeniVal where- uniplate x = (Zero, \Zero -> x)--instance Show GeniVal where- show (GConst x) = concat $ intersperse "|" x- show (GVar x) = '?':x- show GAnon = "?_"--isConst :: GeniVal -> Bool-isConst (GConst _) = True-isConst _ = False--isVar :: GeniVal -> Bool-isVar (GVar _) = True-isVar _ = False--isAnon :: GeniVal -> Bool-isAnon GAnon = True-isAnon _ = False---- | (assumes that it's a GConst!)-fromGConst :: GeniVal -> [String]-fromGConst (GConst x) = x-fromGConst x = error ("fromGConst on " ++ show x)---- | (assumes that it's a GVar!)-fromGVar :: GeniVal -> String-fromGVar (GVar x) = x-fromGVar x = error ("fromGVar on " ++ show x)---- ------------------------------------------------------------------------- Helper types--- ------------------------------------------------------------------------type Subst = Map.Map String GeniVal---- ------------------------------------------------------------------------- Unification--- -------------------------------------------------------------------------- | 'unify' performs unification on two lists of 'GeniVal'. If--- unification succeeds, it returns @Just (r,s)@ where \verb!r! is--- the result of unification and \verb!s! is a list of substitutions that--- this unification results in.-unify :: Monad m => [GeniVal] -> [GeniVal] -> m ([GeniVal], Subst)-unify l1 l2 = repropagate `liftM` helper l1 l2- where- repropagate (xs, sub) = (replace sub xs, sub)- helper [] l2 = return (l2, Map.empty)- helper l1 [] = return (l1, Map.empty)- helper (h1:t1) (h2:t2) =- case unifyOne h1 h2 of- Failure -> fail $ "unification failure between " ++ show h1 ++ " and " ++ show h2- SuccessRep v g -> prepend `liftM` helper t1b t2b- where- s = (v,g)- t1b = replaceOne s t1- t2b = replaceOne s t2- prepend = (g:) *** prependToSubst s- SuccessSans g -> first (g:) `liftM` helper t1 t2---- | Note that the first Subst is assumed to come chronologically--- before the second one; so merging @{ X -> Y }@ and @{ Y -> 3 }@--- should give us @{ X -> 3; Y -> 3 }@;------ See 'prependToSubst' for a warning!-mergeSubst :: Subst -> Subst -> Subst-mergeSubst sm1 sm2 = Map.foldWithKey (curry prependToSubst) sm2 sm1---- | Add to variable replacement to a 'Subst' that logical comes before--- the other stuff in it. So for example, if we have @Y -> foo@--- and we want to insert @X -> Y@, we notice that, in fact, @Y@ has--- already been replaced by @foo@, so we add @X -> foo@ instead------ Note that it is undefined if you try to append something like--- @Y -> foo@ to @Y -> bar@, because that would mean that unification--- is broken-prependToSubst :: (String,GeniVal) -> Subst -> Subst-prependToSubst (v, gr@(GVar r)) sm =- case Map.lookup v sm of- Just v2 -> geniBug . unlines $- [ "prependToSubst: GenI just tried to prepend the substitution"- , " " ++ show (GVar v) ++ " -> " ++ show gr- , "to one where where "- , " " ++ show (GVar v) ++ " -> " ++ show v2- , "is slated to occur afterwards."- , ""- , "This could mean that either"- , " (a) the core unification algorithm is broken"- , " (b) we failed to propagate a value somewhere or"- , " (c) we are attempting unification without renaming."- ]- Nothing -> Map.insert v gr2 sm- where gr2 = fromMaybe gr $ Map.lookup r sm-prependToSubst (v, gr) sm = Map.insert v gr sm---- ------------------------------------------------------------------------- Core unification--- TODO: would continuation passing style make this more efficient?--- ------------------------------------------------------------------------data UnificationResult = SuccessSans GeniVal- | SuccessRep String GeniVal- | Failure---- | See source code for details-unifyOne :: GeniVal -> GeniVal -> UnificationResult-unifyOne g GAnon = SuccessSans g-unifyOne GAnon g = SuccessSans g-unifyOne (GVar v) gc@(GConst _) = SuccessRep v gc-unifyOne gc@(GConst _) (GVar v) = SuccessRep v gc-unifyOne (GConst v1) (GConst v2) =- case v1 `intersect` v2 of- [] -> Failure- newV -> SuccessSans (GConst newV)-unifyOne x1@(GVar v1) (GVar v2) =- if v1 == v2- then SuccessSans x1- else SuccessRep v2 x1---- ------------------------------------------------------------------------- Variable substitution--- ------------------------------------------------------------------------replace :: DescendGeniVal a => Subst -> a -> a-replace m | Map.null m = id-replace m = descendGeniVal (replaceMapG m)--replaceOne :: DescendGeniVal a => (String, GeniVal) -> a -> a-replaceOne = descendGeniVal . replaceOneG---- | Here it is safe to say (X -> Y; Y -> Z) because this would be crushed--- down into a final value of (X -> Z; Y -> Z)-replaceList :: DescendGeniVal a => [(String,GeniVal)] -> a -> a-replaceList = replace . foldl' update Map.empty- where- update m (s1,s2) = Map.insert s1 s2 $ Map.map (replaceOne (s1,s2)) m--replaceMapG :: Subst -> GeniVal -> GeniVal-replaceMapG m v@(GVar v_) = {-# SCC "replaceMapG" #-} Map.findWithDefault v v_ m-replaceMapG _ v = {-# SCC "replaceMapG" #-} v--replaceOneG :: (String, GeniVal) -> GeniVal -> GeniVal-replaceOneG (s1, s2) (GVar v_) | v_ == s1 = {-# SCC "replaceOneG" #-} s2-replaceOneG _ v = {-# SCC "replaceOneG" #-} v---- ------------------------------------------------------------------------- Performance--- ------------------------------------------------------------------------instance NFData GeniVal- where rnf (GConst x1) = rnf x1- rnf (GVar x1) = rnf x1- rnf (GAnon) = ()---- ------------------------------------------------------------------------- Genericity--- ------------------------------------------------------------------------class DescendGeniVal a where- descendGeniVal :: (GeniVal -> GeniVal) -> a -> a--instance DescendGeniVal GeniVal where- descendGeniVal f = f--instance (Functor f, DescendGeniVal a) => DescendGeniVal (f a) where- descendGeniVal = fmap . descendGeniVal---- ------------------------------------------------------------------------- Testing--- ------------------------------------------------------------------------testSuite = testGroup "unification"- [ testProperty "self" prop_unify_sym- , testProperty "anonymous variables" prop_unify_anon- , testProperty "symmetry" prop_unify_sym- , testBackPropagation- ]---- | Unifying something with itself should always succeed-prop_unify_self :: [GeniVal] -> Property-prop_unify_self x =- (all qc_not_empty_GConst) x ==>- case unify x x of- Nothing -> False- Just unf -> fst unf == x---- | Unifying something with only anonymous variables should succeed and return--- the same result.-prop_unify_anon :: [GeniVal] -> Bool-prop_unify_anon x =- case unify x y of- Nothing -> False- Just unf -> fst unf == x- where --- y = replicate (length x) GAnon---- | Unification should be symmetrical. We can't guarantee these if there--- are cases where there are variables in the same place on both sides, so we--- normalise the sides so that this doesn't happen.-prop_unify_sym :: [GeniVal] -> [GeniVal] -> Property-prop_unify_sym x y =- let u1 = (unify x y) :: Maybe ([GeniVal],Subst)- u2 = unify y x- --- notOverlap (GVar _, GVar _) = False- notOverlap _ = True- in (all qc_not_empty_GConst) x &&- (all qc_not_empty_GConst) y &&- all (notOverlap) (zip x y) ==> u1 == u2--testBackPropagation =- testGroup "back propagation"- [ testCase "unify left/right" $ assertEqual "" expected $ unify left right- , testCase "unify right/left" $ assertEqual "" expected $ unify right left- ]- where- n = 3- cx = GConst ["X"]- leftStrs = map show [1..n]- left = map GVar leftStrs- right = drop 1 left ++ [cx]- expected = Just (expectedResult, expectedSubst)- expectedResult = replicate n cx- expectedSubst = Map.fromList $ zip leftStrs (repeat cx)---- ------------------------------------------------------------------------- Testing--- -------------------------------------------------------------------------- Definition of Arbitrary GeniVal for QuickCheck-newtype GTestString = GTestString String-newtype GTestString2 = GTestString2 String--fromGTestString :: GTestString -> String-fromGTestString (GTestString s) = s--fromGTestString2 :: GTestString2 -> String-fromGTestString2 (GTestString2 s) = s--instance Arbitrary GTestString where- arbitrary =- oneof $ map (return . GTestString) $- [ "a", "apple" , "b", "banana", "c", "carrot", "d", "durian"- , "e", "eggplant", "f", "fennel" , "g", "grape" ]- coarbitrary = error "no implementation of coarbitrary for GTestString"--instance Arbitrary GTestString2 where- arbitrary =- oneof $ map (return . GTestString2) $- [ "X", "Y", "Z", "H", "I", "J", "P", "Q", "R", "S", "T", "U" ]- coarbitrary = error "no implementation of coarbitrary for GTestString2"+{-# LANGUAGE OverlappingInstances, FlexibleInstances, TemplateHaskell #-}+{-# LANGUAGE DeriveDataTypeable #-}+module NLP.GenI.GeniVal+ ( -- * GeniVal+ GeniVal, gLabel, gConstraints+ , mkGConst, mkGConstNone, mkGVar, mkGVarNone, mkGAnon+ -- ** queries and manipulation+ , isVar, isAnon, isConst, singletonVal+ , crushOne+ -- * Unification and subsumption+ --+ -- ** Finalisation+ --+ -- Before you do any unification/subsumption, you should finalise all+ -- the variables in all the objects (a one time alpha-conversion type+ -- thing)+ , finaliseVars, finaliseVarsById+ -- ** Unification+ , unify, UnificationResult(..), Subst, appendSubst+ -- ** subsumption+ , subsumeOne, allSubsume -instance Arbitrary GeniVal where- arbitrary = oneof [ return $ GAnon,- fmap (GVar . fromGTestString2) arbitrary,- fmap (GConst . nub . sort . map fromGTestString) arbitrary ]- coarbitrary = error "no implementation of coarbitrary for GeniVal"+ -- * Traversing GeniVal containers+ , DescendGeniVal(..), Collectable(..), Idable(..)+ , replace, replaceList+ ) where -qc_not_empty_GConst :: GeniVal -> Bool-qc_not_empty_GConst (GConst []) = False-qc_not_empty_GConst _ = True+import NLP.GenI.GeniVal.Internal
+ src/NLP/GenI/GeniVal/Internal.hs view
@@ -0,0 +1,428 @@+-- GenI surface realiser+-- Copyright (C) 2009 Eric Kow+-- Copyright (C) 2005 Carlos Areces+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++{-# LANGUAGE OverlappingInstances, FlexibleInstances, TemplateHaskell #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}+module NLP.GenI.GeniVal.Internal where++-- import Debug.Trace -- for test stuff+import Control.Arrow (first, (***))+import Control.Monad (liftM)+import Data.Binary+import Data.List+import Data.Maybe (fromMaybe, isNothing, isJust)+import Data.Generics (Data)+import Data.Typeable (Typeable)+import qualified Data.Map as Map++import Data.Text ( Text )+import qualified Data.Text as T++import Control.DeepSeq++import Data.FullList ( FullList, fromFL, Listable(..), sortNub )+import NLP.GenI.General (geniBug, quoteText, isGeniIdentLetter)+import NLP.GenI.GeniShow+import NLP.GenI.Pretty++-- | constant : no label, just constraints+-- variable : label, with or without constraints+-- anonymous : no label, no constraints+data GeniVal = GeniVal { gLabel :: Maybe Text+ , gConstraints :: Maybe (FullList Text)+ }+ deriving (Eq,Ord, Data, Typeable)++-- | 'mkGConst' @x :! []@ creates a single constant. 'mkGConst' @x :! xs@+-- creates an atomic disjunction. It makes no difference which of the values+-- you supply for @x@ and @xs@ as they will be sorted and nubed anyway.+mkGConst :: FullList Text -- ^ non-empty list+ -> GeniVal+mkGConst cs_ = GeniVal Nothing (Just cs)+ where+ cs = sortNub cs_++mkGConstNone :: Text -> GeniVal+mkGConstNone x = mkGConst (x !: [])++mkGVar :: Text -> Maybe (FullList Text) -> GeniVal+mkGVar x mxs = GeniVal (Just x) (sortNub `fmap` mxs)++mkGVarNone :: Text -> GeniVal+mkGVarNone x = mkGVar x Nothing++mkGAnon :: GeniVal+mkGAnon = GeniVal Nothing Nothing++{-+instance Show GeniVal where+ show = T.unpack . prettyGeniVal+-}++instance Pretty GeniVal where+ pretty = geniShowText++instance GeniShow GeniVal where+ geniShowText gv =+ case gv of+ GeniVal Nothing Nothing -> showLabel "_"+ GeniVal Nothing (Just cs) -> showConstraints cs+ GeniVal (Just l) Nothing -> showLabel l+ GeniVal (Just l) (Just cs) ->+ showLabel l `T.append` "/" `T.append` showConstraints cs+ where+ showLabel l = '?' `T.cons` l+ showConstraints = T.intercalate "|" . map maybeQuote . fromFL -- FIXME push down+ maybeQuote x | T.null x = quoteText ""+ | "-" `T.isPrefixOf` x = quoteText x -- could be interpreted as+ | "+" `T.isPrefixOf` x = quoteText x -- semantic polarities+ | T.any naughty x = quoteText x+ | otherwise = x+ naughty x = not (isGeniIdentLetter x) || x `elem` "_?/"++isConst :: GeniVal -> Bool+isConst = isNothing . gLabel++singletonVal :: GeniVal -> Maybe Text+singletonVal v =+ case fmap fromFL (gConstraints v) of+ Just [o] -> Just o+ _ -> Nothing++isVar :: GeniVal -> Bool+isVar = isJust . gConstraints++isAnon :: GeniVal -> Bool+isAnon (GeniVal Nothing Nothing) = True+isAnon _ = False++-- ----------------------------------------------------------------------+-- Helper types+-- ----------------------------------------------------------------------++type Subst = Map.Map Text GeniVal++prettySubst :: Subst -> Text+prettySubst =+ T.unwords . map sho . Map.toList+ where+ sho (v,s) = v `T.append` "<-" `T.append` pretty s++-- ----------------------------------------------------------------------+-- Unification and subsumption+-- ----------------------------------------------------------------------++-- | 'unify' performs unification on two lists of 'GeniVal'. If+-- unification succeeds, it returns @Just (r,s)@ where @r@ is+-- the result of unification and \verb!s! is a list of substitutions that+-- this unification results in.+unify :: Monad m => [GeniVal] -> [GeniVal] -> m ([GeniVal], Subst)+unify = unifyHelper unifyOne++-- | @l1 `allSubsume` l2@ returns the result of @l1 `unify` l2@ if+-- doing a simultaneous traversal of both lists, each item in+-- @l1@ subsumes the corresponding item in @l2@+allSubsume :: Monad m => [GeniVal] -> [GeniVal] -> m ([GeniVal], Subst)+allSubsume = unifyHelper subsumeOne++unifyHelper :: Monad m+ => (GeniVal -> GeniVal -> UnificationResult)+ -> [GeniVal]+ -> [GeniVal]+ -> m ([GeniVal], Subst)+unifyHelper f ll1 ll2 = repropagate `liftM` helper ll1 ll2+ where+ repropagate (xs, sub) = (replace sub xs, sub)+ helper [] l2 = return (l2, Map.empty)+ helper l1 [] = return (l1, Map.empty)+ helper (h1:t1) (h2:t2) =+ case f h1 h2 of+ Failure -> fail . T.unpack . T.unwords $+ [ "unification failure between"+ , pretty h1, "and"+ , pretty h2+ ]+ SuccessRep v g -> prepend `liftM` helper t1b t2b+ where+ s = (v,g)+ t1b = replaceOne s t1+ t2b = replaceOne s t2+ prepend = (g:) *** prependToSubst s+ SuccessRep2 v1 v2 g -> prepend `liftM` helper t1b t2b+ where+ s1 = (v1,g)+ s2 = (v2,g)+ t1b = replaceOne s2 . replaceOne s1 $ t1+ t2b = replaceOne s2 . replaceOne s1 $ t2+ prepend = (g:) *** (prependToSubst s1 . prependToSubst s2)+ SuccessSans g -> first (g:) `liftM` helper t1 t2++-- | Note that the first Subst is assumed to come chronologically+-- before the second one; so merging @{ X -> Y }@ and @{ Y -> 3 }@+-- should give us @{ X -> 3; Y -> 3 }@;+--+-- See 'prependToSubst' for a warning!+appendSubst :: Subst -> Subst -> Subst+appendSubst sm1 sm2 = Map.foldrWithKey (curry prependToSubst) sm2 sm1++-- | Add to variable replacement to a 'Subst' that logical comes before+-- the other stuff in it. So for example, if we have @Y -> foo@+-- and we want to insert @X -> Y@, we notice that, in fact, @Y@ has+-- already been replaced by @foo@, so we add @X -> foo@ instead+--+-- Note that it is undefined if you try to append something like+-- @Y -> foo@ to @Y -> bar@, because that would mean that unification+-- is broken+prependToSubst :: (Text,GeniVal) -> Subst -> Subst+prependToSubst (v, gr@(GeniVal (Just r) _)) sm =+ case Map.lookup v sm of+ Just v2 -> geniBug . unlines $+ [ "prependToSubst: GenI just tried to prepend the substitution"+ , " " ++ prettyStr (mkGVar v Nothing) ++ " -> " ++ prettyStr gr+ , "to one where where "+ , " " ++ prettyStr (mkGVar v Nothing) ++ " -> " ++ prettyStr v2+ , "is slated to occur afterwards."+ , ""+ , "This could mean that either"+ , " (a) the core unification algorithm is broken"+ , " (b) we failed to propagate a value somewhere or"+ , " (c) we are attempting unification without renaming."+ ]+ Nothing -> Map.insert v gr2 sm+ where gr2 = fromMaybe gr $ Map.lookup r sm+prependToSubst (v, gr) sm = Map.insert v gr sm++-- ----------------------------------------------------------------------+-- Core unification+-- TODO: would continuation passing style make this more efficient?+-- ----------------------------------------------------------------------++data UnificationResult = SuccessSans GeniVal+ | SuccessRep Text GeniVal+ | SuccessRep2 Text Text GeniVal+ | Failure++-- | See source code for details+--+-- Note that we assume that it's acceptable to generate new+-- variable names by appending an 'x' to them; this assumption+-- is only safe if the variables have gone through the function+-- 'finaliseVarsById' or have been pre-processed and rewritten+-- with some kind of common suffix to avoid an accidental match+unifyOne :: GeniVal -> GeniVal -> UnificationResult+unifyOne (GeniVal Nothing Nothing) g = SuccessSans g+unifyOne g (GeniVal Nothing Nothing) = SuccessSans g+unifyOne g1 g2 =+ maybe Failure constrSuccess (intersectConstraints gc1 gc2)+ where+ gc1 = gConstraints g1+ gc2 = gConstraints g2+ constrSuccess cs =+ case (gLabel g1, gLabel g2) of+ (Nothing, Nothing) -> SuccessSans (GeniVal Nothing cs)+ (Nothing, Just v) -> SuccessRep v (GeniVal Nothing cs)+ (Just v, Nothing) -> SuccessRep v (GeniVal Nothing cs)+ (Just v1, Just v2) -> bothLabeled cs v1 v2+ bothLabeled cs v1 v2+ | v1 == v2 && gc1 /= gc2 = geniBug constraintBug+ | v1 == v2 = SuccessSans g1+ | gc1 == gc2 = successSameConstraints cs v1 v2+ | otherwise = successDiffConstraints cs v1 v2+ successSameConstraints cs v1 v2 =+ SuccessRep (min v1 v2) $ GeniVal (Just (max v1 v2)) cs+ successDiffConstraints cs v1 v2 =+ -- min/max stuff for symmetry+ SuccessRep2 (min v1 v2) (max v1 v2) $+ GeniVal (Just (max v1 v2 `T.append` "-g")) cs+ constraintBug = unwords+ [ "I just tried to unify variable with itself,"+ , "but it has mismatching constraints:"+ , prettyStr g1, "vs."+ , prettyStr g2+ ]++intersectConstraints :: Eq a => Maybe (FullList a) -> Maybe (FullList a) -> Maybe (Maybe (FullList a))+intersectConstraints Nothing cs = Just cs+intersectConstraints cs Nothing = Just cs+intersectConstraints (Just v1) (Just v2) =+ case fromFL v1 `intersect` fromFL v2 of+ [] -> Nothing+ (x:xs) -> Just (Just (x !: xs))++-- ----------------------------------------------------------------------+-- Core subsumption+-- ----------------------------------------------------------------------++-- | 'subsumeOne' @x y@ returns the same result as @unifyOne x y@ if @x@+-- subsumes @y@ or 'Failure' otherwise+subsumeOne :: GeniVal -> GeniVal -> UnificationResult+subsumeOne g1@(GeniVal _ (Just cs1)) g2@ (GeniVal _ (Just cs2)) =+ if fromFL cs1 `subset` fromFL cs2 then unifyOne g1 g2 else Failure+ where+ subset x y = all (`elem` y) x+subsumeOne (GeniVal _ (Just _)) (GeniVal _ Nothing) = Failure+subsumeOne g1@(GeniVal _ Nothing) g2 = unifyOne g1 g2++-- ----------------------------------------------------------------------+-- Variable substitution+-- ----------------------------------------------------------------------++replace :: DescendGeniVal a => Subst -> a -> a+replace m | Map.null m = id+replace m = descendGeniVal (replaceMapG m)++replaceOne :: DescendGeniVal a => (Text, GeniVal) -> a -> a+replaceOne = descendGeniVal . replaceOneG++-- | Here it is safe to say (X -> Y; Y -> Z) because this would be crushed+-- down into a final value of (X -> Z; Y -> Z)+replaceList :: DescendGeniVal a => [(Text,GeniVal)] -> a -> a+replaceList = replace . foldl' update Map.empty+ where+ update m (s1,s2) = Map.insert s1 s2 $ Map.map (replaceOne (s1,s2)) m++replaceMapG :: Subst -> GeniVal -> GeniVal+replaceMapG m v@(GeniVal (Just v_) _) = Map.findWithDefault v v_ m+replaceMapG _ v = v++replaceOneG :: (Text, GeniVal) -> GeniVal -> GeniVal+replaceOneG (s1, s2) (GeniVal (Just v_) _) | v_ == s1 = s2+replaceOneG _ v = v++-- ----------------------------------------------------------------------+-- Variable collection and renaming+-- ----------------------------------------------------------------------++type CollectedVar = (Text, Maybe (FullList Text))++-- | A 'Collectable' is something which can return its variables as a+-- map from the variable to the number of times that variable occurs+-- in it.+--+-- Important invariant: if the variable does not occur, then it does+-- not appear in the map (ie. all counts must be >= 1 or the item+-- does not occur at all)+--+-- By variables, what I most had in mind was the GVar values in a+-- GeniVal. This notion is probably not very useful outside the context of+-- alpha-conversion task, but it seems general enough that I'll keep it+-- around for a good bit, until either some use for it creeps up, or I find+-- a more general notion that I can transform this into.+class Collectable a where+ collect :: a -> Map.Map CollectedVar Int -> Map.Map CollectedVar Int++instance Collectable a => Collectable (Maybe a) where+ collect Nothing s = s+ collect (Just x) s = collect x s++instance (Collectable a => Collectable [a]) where+ collect l s = foldr collect s l++instance Collectable GeniVal where+ collect (GeniVal (Just v) cs) s = Map.insertWith' (+) (v,cs) 1 s+ collect (GeniVal Nothing _) s = s++-- | An Idable is something that can be mapped to a unique id.+-- You might consider using this to implement Ord, but I won't.+-- Note that the only use I have for this so far (20 dec 2005)+-- is in alpha-conversion.+class Idable a where+ idOf :: a -> Integer++-- | Anonymise any variable that occurs only once in the object+anonymiseSingletons :: (Collectable a, DescendGeniVal a) => a -> a+anonymiseSingletons x =+ replace subst x+ where+ subst = Map.map (const mkGAnon) . Map.filter (== 1)+ -- merge counts for same var, different constraints+ . Map.fromListWith (+) . map (first fst) . Map.toList+ $ collect x Map.empty++-- 'finaliseVarsById' appends a unique suffix to all variables in+-- an object. This avoids us having to alpha convert all the time+-- and relies on the assumption finding that a unique suffix is+-- possible.+finaliseVarsById :: (Collectable a, DescendGeniVal a, Idable a) => a -> a+finaliseVarsById x = finaliseVars ('-' `T.cons` (T.pack . show $ idOf x)) x++-- | 'finaliseVars' does the following:+--+-- * (if suffix is non-null) appends a suffix to all variable names+-- to ensure global uniqueness+--+-- * anonymises any singleton variables+---+--- * intersects constraints for for all variables within the same+--- object+finaliseVars :: (Collectable a, DescendGeniVal a) => Text -> a -> a+finaliseVars suffix x = {-# SCC "finaliseVars" #-}+ replace subst (anonymiseSingletons x)+ where+ subst :: Subst+ subst = Map.mapWithKey convert vars+ vars = Map.fromListWithKey isect $ Map.keys (collect x Map.empty)+ -- TODO: ugh: this is maybe not ideal: if a variable has impossible+ -- constraints (eg. ?X/cat cannot unify with ?X/dog, but it can+ -- unify with ?X/cat vs ?X/dog|cat => ?X/cat), we hardcode it to a+ -- value that should not be able to unify with anything+ isect k xi yi =+ fromMaybe (Just (impossibleC k)) $ intersectConstraints xi yi+ convert v = GeniVal (Just (v `T.append` suffix))+ impossibleC v = ("ERROR_impossible_constraints_" `T.append` v `T.append` suffix)+ !: []++-- ----------------------------------------------------------------------+-- Fancy disjunction+-- ----------------------------------------------------------------------++crushOne :: [GeniVal] -> Maybe GeniVal+crushOne [] = Nothing+crushOne [gs] = Just gs+crushOne gs =+ if any isNothing gcs+ then Nothing+ else case concat [ fromFL c | Just c <- gcs ] of+ [] -> Nothing+ (c:cs) -> Just (mkGConst (c !: cs))+ where+ gcs = map gConstraints gs++crushList :: [[GeniVal]] -> Maybe [GeniVal]+crushList = mapM crushOne++-- ----------------------------------------------------------------------+-- Genericity+-- ----------------------------------------------------------------------++class DescendGeniVal a where+ descendGeniVal :: (GeniVal -> GeniVal) -> a -> a++instance DescendGeniVal GeniVal where+ descendGeniVal f = f++instance (Functor f, DescendGeniVal a) => DescendGeniVal (f a) where+ descendGeniVal = fmap . descendGeniVal++instance NFData GeniVal where+ rnf (GeniVal x y) = rnf x `seq` rnf y++instance Binary GeniVal where+ put (GeniVal a b) = put a >> put b+ get = get >>= \a -> get >>= \b -> return (GeniVal a b)
− src/NLP/GenI/Graphviz.hs
@@ -1,214 +0,0 @@-{-# OPTIONS -fglasgow-exts #-}--{-- GenI surface realiser- Copyright (C) 2005 Carlos Areces and Eric Kow- - This program is free software; you can redistribute it and/or- modify it under the terms of the GNU General Public License- as published by the Free Software Foundation; either version 2- of the License, or (at your option) any later version.- - This program is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.- - You should have received a copy of the GNU General Public License- along with this program; if not, write to the Free Software- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.--}--{- | Graphviz is an open source tool which converts an abstract- representation of a graph (node foo is connected to node bar, etc.)- into a nicely laid out graphic. This module contains methods - to invoke graphviz and to convert graphs and trees to its input format.-- You can download this (open source) tool at- <http://www.research.att.com/sw/tools/graphviz>--}--module NLP.GenI.Graphviz-where--import Control.Monad(when)-import Data.List(intersperse)-import Data.Tree-import System.IO ( hClose )-import System.IO.UTF8-import Prelude hiding ( writeFile )-import System.Exit(ExitCode)--import NLP.GenI.SysGeni(waitForProcess, runInteractiveProcess)--{- |- Data structures which can be visualised with GraphViz should- implement this class. Note the first argument to graphvizShowGraph is- so that you can parameterise your show function (i.e. pass in- flags to change the way you show particular object). Note- that by default, all graphs are treated as directed graphs. You- can hide this by turning off edge arrows.--}-class GraphvizShow flag b where- graphvizShowGraph :: flag -> b -> String- graphvizShowAsSubgraph :: flag -- ^ flag- -> String -- ^ prefix- -> b -- ^ item- -> String -- ^ gv output - graphvizLabel :: flag -- ^ flag- -> b -- ^ item- -> String -- ^ gv output- graphvizParams :: flag -> b -> [String] -- graphvizShowGraph f b = - let l = graphvizLabel f b- in "digraph {\n" - ++ (unlines $ graphvizParams f b)- ++ graphvizShowAsSubgraph f "_" b ++ "\n"- ++ (if null l then "" else " label = \"" ++ l ++ "\";\n")- ++ "}"- graphvizLabel _ _ = ""- graphvizParams _ _ = []--class GraphvizShowNode flag b where- graphvizShowNode :: flag -- ^ flag - -> String -- ^ prefix - -> b -- ^ item - -> String -- ^ gv output---- | Things which are meant to be displayed within some other graph--- as (part) of a node label-class GraphvizShowString flag b where- graphvizShow :: flag -- ^ flag- -> b -- ^ item- -> String -- ^ gv output---- | Note: the 'dotFile' argument allows you to save the intermediary--- dot output to a file. You can pass in the empty string if you don't-toGraphviz :: (GraphvizShow f a) => f - -> a - -> String -- ^ the 'dotFile'- -> String -> IO ExitCode -toGraphviz p x dotFile outputFile = do- graphviz (graphvizShowGraph p x) dotFile outputFile---- ------------------------------------------------------------------------ useful utility functions--- -----------------------------------------------------------------------gvNewline :: String-gvNewline = "\\n"--gvUnlines :: [String] -> String-gvUnlines = concat . (intersperse gvNewline)--gvSubgraph :: String -> String-gvSubgraph g = "subgraph {\n" ++ g ++ "}\n"---- | The Graphviz string for a node. Note that we make absolutely no--- effort to escape any characters for you; so if you need to protect--- anything from graphviz, you're on your own-gvNode :: String -- ^ the node name- -> String -- ^ the label (may be empty)- -> [(String,String)] -- ^ any other parameters- -> String-gvNode name label params = - " " ++ name ++ " " ++ (gvLabelAndParams label params) ++ "\n"---- | The Graphviz string for a connection between two nodes. --- Same disclaimer as 'gvNode' applies.-gvEdge :: String -- ^ the 'from' node- -> String -- ^ the 'to' node- -> String -- ^ the label (may be empty)- -> [(String,String)] -- ^ any other parameters - -> String-gvEdge from to label params = - " " ++ from ++ " -> " ++ to ++ (gvLabelAndParams label params) ++ "\n"--gvLabelAndParams :: String -> [(String,String)] -> String-gvLabelAndParams l p = - gvParams $ if null l then p else ("label", l) : p--gvParams :: [(String,String)] -> String-gvParams [] = ""-gvParams p = "[ " ++ (concat $ intersperse ", " $ map showPair p) ++ " ]"- where showPair (a,v) = a ++ "=\"" ++ v ++ "\""---- ------------------------------------------------------------------------ some instances --- -----------------------------------------------------------------------instance (GraphvizShow f b) => GraphvizShow f (Maybe b) where- graphvizShowAsSubgraph _ _ Nothing = ""- graphvizShowAsSubgraph f p (Just b) = graphvizShowAsSubgraph f p b -- graphvizLabel _ Nothing = ""- graphvizLabel f (Just b) = graphvizLabel f b-- graphvizParams _ Nothing = [] - graphvizParams f (Just b) = graphvizParams f b---- | Displays a tree in graphviz format. -{- Note that we could make this an- instance of GraphvizShow, but I'm not too sure about the wisdom of- such a move. -- Maybe if we had some really super-sophisticated types in Haskell, where- we can define this as the default instance which could be overrided by- something more specific, that would be cool.-- The prefix argument is interpreted as the name of the top node. Node- names below are basically Gorn addresses (e.g. n0x2x3 means 3rd child of- the 2nd child of the root) to keep them distinct. Note : We use the- letter `x' as seperator because graphviz will choke on `.' or `-', even- underscore. -}-gvShowTree :: (GraphvizShowNode f n) => - (n->[(String,String)]) -- ^ function to convert a node to a list of graphviz parameters for the edge - -> f -- ^ GraphvizShow flag- -> String -- ^ node prefix- -> (Tree n) -- ^ the tree- -> String-gvShowTree edgeFn f prefix t = - "edge [ arrowhead = none ]\n" ++ gvShowTreeHelper edgeFn f prefix t --gvShowTreeHelper :: forall n . forall f . (GraphvizShowNode f n) => (n->[(String,String)]) -> f -> String -> (Tree n) -> String-gvShowTreeHelper edgeFn f prefix (Node node l) = - let showNode = graphvizShowNode f prefix - showKid :: Integer -> Tree n -> String- showKid index kid = - gvShowTreeHelper edgeFn f kidname kid ++ " " - ++ (gvEdge prefix kidname "" (edgeFn node))- where kidname = prefix ++ "x" ++ (show index)- in showNode node ++ "\n" ++ (concat $ zipWith showKid [0..] l)---- ------------------------------------------------------------------------ invocation --- ------------------------------------------------------------------------- | Calls graphviz. If the second argument is the empty string, then we--- just send stuff directly to dot's stdin--graphviz :: String -- ^ graphviz's dot format.- -> String -- ^ the name of the file graphviz should write the dot - -> String -- ^ the name of the file graphviz should write its output - -> IO ExitCode---- We write the dot String to a temporary file which we then feed to graphviz.--- This is avoid complications with fork and pipes. We use png output even--- though it's uglier, because we don't have a wxhaskell widget that can --- display postscript... do we?--graphviz dot dotFile outputFile = do- let dotArgs' = ["-Gfontname=courier", - "-Nfontname=courier", - "-Efontname=courier", - "-Gcharset=utf-8",- "-Tpng", "-o" ++ outputFile ]- dotArgs = dotArgs' ++ (if (null dotFile) then [] else [dotFile])- -- putStrLn ("sending to graphviz:\n" ++ dot) - when (not $ null dotFile) $ writeFile dotFile dot- (_, toGV, _, pid) <- runInteractiveProcess "dot" dotArgs Nothing Nothing- when (null dotFile) $ do - hPutStrLn toGV dot - hClose toGV- waitForProcess pid
− src/NLP/GenI/GraphvizShow.hs
@@ -1,199 +0,0 @@--- GenI surface realiser--- Copyright (C) 2009 Eric Kow------ This program is free software; you can redistribute it and/or--- modify it under the terms of the GNU General Public License--- as published by the Free Software Foundation; either version 2--- of the License, or (at your option) any later version.------ This program is distributed in the hope that it will be useful,--- but WITHOUT ANY WARRANTY; without even the implied warranty of--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the--- GNU General Public License for more details.------ You should have received a copy of the GNU General Public License--- along with this program; if not, write to the Free Software--- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.--{-# LANGUAGE FlexibleInstances, TypeSynonymInstances, FlexibleContexts #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--- | Outputting core GenI data to graphviz.-module NLP.GenI.GraphvizShow-where--import Data.List(intersperse,nub)-import Data.List.Split (wordsBy)-import Data.Maybe(listToMaybe)--import NLP.GenI.Tags- ( TagElem, TagDerivation, idname,- tsemantics, ttree,- DerivationStep(..),- )-import NLP.GenI.Btypes (GeniVal(GConst), AvPair(..),- GNode(..), GType(..), Flist,- isConst,- showSem,- )-import NLP.GenI.Graphviz- ( gvUnlines, gvNewline- , GraphvizShow(graphvizShowAsSubgraph, graphvizLabel, graphvizParams)- , GraphvizShowNode(graphvizShowNode)- , GraphvizShowString(graphvizShow)- , gvNode, gvEdge, gvShowTree- )---- ------------------------------------------------------------------------- For GraphViz--- ------------------------------------------------------------------------type GvHighlighter a = a -> (a, Maybe String)--nullHighlighter :: GvHighlighter GNode-nullHighlighter a = (a,Nothing)--instance GraphvizShow Bool TagElem where- graphvizShowAsSubgraph sf = graphvizShowAsSubgraph (sf, nullHighlighter)- graphvizLabel sf = graphvizLabel (sf, nullHighlighter )- graphvizParams sf = graphvizParams (sf, nullHighlighter)---instance GraphvizShow (Bool, GvHighlighter GNode) TagElem where- graphvizShowAsSubgraph (sf,hfn) prefix te =- (gvShowTree (\_->[]) sf (prefix ++ "DerivedTree0") $- fmap hfn $ ttree te)-- graphvizLabel _ te =- -- we display the tree semantics as the graph label- let treename = "name: " ++ (idname te)- semlist = "semantics: " ++ (showSem $ tsemantics te)- in gvUnlines [ treename, semlist ]-- graphvizParams _ _ =- [ "fontsize = 10", "ranksep = 0.3"- , "node [fontsize=10]"- , "edge [fontsize=10 arrowhead=none]" ]---- ------------------------------------------------------------------------- Helper functions for the TagElem GraphvizShow instance--- ------------------------------------------------------------------------instance GraphvizShowNode (Bool) (GNode, Maybe String) where- -- compact -> (node, mcolour) -> String- graphvizShowNode detailed prefix (gn, mcolour) =- let -- attributes- filledParam = ("style", "filled")- fillcolorParam = ("fillcolor", "lemonchiffon")- shapeRecordParam = ("shape", "record")- shapePlaintextParam = ("shape", "plaintext")- --- colorParams = case mcolour of- Nothing -> []- Just c -> [ ("fontcolor", c) ]- shapeParams = if detailed- then [ shapeRecordParam, filledParam, fillcolorParam ]- else [ shapePlaintextParam ]- -- content- stub = showGnStub gn- extra = showGnDecorations gn- summary = if null extra then stub- else "{" ++ stub ++ "|" ++ extra ++ "}"- --- body = if not detailed then graphvizShow_ gn- else "{" ++ summary- ++ (barAnd.showFs $ gup gn)- ++ (maybeShow (barAnd.showFs) $ gdown gn)- ++ "}"- where barAnd x = "|" ++ x- showFs = gvUnlines . (map graphvizShow_)- in gvNode prefix body (shapeParams ++ colorParams)--instance GraphvizShowString () GNode where- graphvizShow () gn =- let stub = showGnStub gn- extra = showGnDecorations gn- in stub ++ extra--instance GraphvizShowString () AvPair where- graphvizShow () (AvPair a v) = a ++ ":" ++ graphvizShow_ v--instance GraphvizShowString () GeniVal where- graphvizShow () (GConst x) = concat $ intersperse " ! " x- graphvizShow () x = show x--showGnDecorations :: GNode -> String-showGnDecorations gn =- case gtype gn of- Subs -> "↓"- Foot -> "*"- _ -> if gaconstr gn then "ᴺᴬ" else ""--showGnStub :: GNode -> String-showGnStub gn =- let cat = case getGnVal gup "cat" gn of- Nothing -> ""- Just v -> graphvizShow_ v- --- getIdx f =- case getGnVal f "idx" gn of- Nothing -> ""- Just v -> if isConst v then graphvizShow_ v else ""- idxT = getIdx gup- idxB = getIdx gdown- idx = idxT ++ (maybeShow_ "." idxB)- --- lexeme = concat $ intersperse "!" $ glexeme gn- in concat $ intersperse ":" $ filter (not.null) [ cat, idx, lexeme ]--getGnVal :: (GNode -> Flist) -> String -> GNode -> Maybe GeniVal-getGnVal getFeat attr gn =- listToMaybe [ v | AvPair a v <- getFeat gn, a == attr ]---- | Apply fn to s if s is not null-maybeShow :: ([a] -> String) -> [a] -> String-maybeShow fn s = if null s then "" else fn s--- | Prefix a string if it is not null-maybeShow_ :: String -> String -> String-maybeShow_ prefix s = maybeShow (prefix++) s--graphvizShow_ :: (GraphvizShowString () a) => a -> String-graphvizShow_ = graphvizShow ()---- ------------------------------------------------------------------------- Derivation tree--- ------------------------------------------------------------------------graphvizShowDerivation :: TagDerivation -> String-graphvizShowDerivation deriv =- if (null histNodes)- then ""- else " node [ shape = plaintext ];\n"- ++ (concatMap showHistNode histNodes)- ++ (concatMap graphvizShowDerivation' deriv)- where showHistNode n = gvNode (gvDerivationLab n) (label n) []- label n = case wordsBy (== ':') n of- name:fam:tree:_ -> name ++ ":" ++ fam ++ gvNewline ++ tree- _ -> n ++ " (geni/gv ERROR)"- histNodes = reverse $ nub $ concatMap (\ (DerivationStep _ c p _) -> [c,p]) deriv--graphvizShowDerivation' :: DerivationStep -> String-graphvizShowDerivation' (DerivationStep substadj child parent _) =- gvEdge (gvDerivationLab parent) (gvDerivationLab child) "" p- where p = if substadj == 'a' then [("style","dashed")] else []---gvDerivationLab :: String -> String-gvDerivationLab xs = "Derivation" ++ gvMunge xs--newlineToSlashN :: Char -> String-newlineToSlashN '\n' = gvNewline-newlineToSlashN x = [x]---- | Node names can't have hyphens in them and newlines within the node--- labels should be represented literally as @\\n@.-gvMunge :: String -> String-gvMunge = map dot2x . filter (/= ':') . filter (/= '-')--dot2x :: Char -> Char-dot2x '.' = 'x'-dot2x c = c
− src/NLP/GenI/GraphvizShowPolarity.lhs
@@ -1,130 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.--\begin{code}-{-# LANGUAGE TypeSynonymInstances #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}-module NLP.GenI.GraphvizShowPolarity-where--import Data.List (intersperse)-import qualified Data.Map as Map--import NLP.GenI.Btypes(showSem)-import NLP.GenI.General(showInterval, isEmptyIntersect)-import NLP.GenI.Polarity(PolAut, PolState(PolSt), NFA(states, transitions), finalSt)-import NLP.GenI.Graphviz(GraphvizShow(..), gvUnlines, gvNewline, gvNode, gvEdge)-import NLP.GenI.Tags(idname)-\end{code}--\begin{code}-instance GraphvizShow () PolAut where- -- we want a directed graph (arrows)- graphvizShowGraph f aut =- "digraph aut {\n"- ++ "rankdir=LR\n"- ++ "ranksep = 0.02\n"- ++ "pack=1\n"- ++ "edge [ fontsize=10 ]\n"- ++ "node [ fontsize=10 ]\n"- ++ graphvizShowAsSubgraph f "aut" aut- ++ "}"-- --- graphvizShowAsSubgraph _ prefix aut =- let st = (concat.states) aut- ids = map (\x -> prefix ++ show x) ([0..] :: [Int])- -- map which permits us to assign an id to a state- stmap = Map.fromList $ zip st ids- in --- gvShowFinal aut stmap- -- any other state should be an ellipse- ++ "node [ shape = ellipse, peripheries = 1 ]\n"- -- draw the states and transitions- ++ (concat $ zipWith gvShowState ids st)- ++ (concat $ zipWith (gvShowTrans aut stmap) ids st )-\end{code}--\begin{code}-gvShowState :: String -> PolState -> String-gvShowState stId st =- -- note that we pass the label param explicitly to allow for null label- gvNode stId "" [ ("label", showSt st) ]- where showSt (PolSt pr ex po) = showPr pr ++ showEx ex ++ showPo po- showPr _ = "" -- (_,pr,_) = pr ++ gvNewline- showPo po = concat $ intersperse "," $ map showInterval po- showEx ex = if null ex then "" else showSem ex ++ gvNewline-\end{code}--Specify that the final states are drawn with a double circle--\begin{code}-gvShowFinal :: PolAut -> Map.Map PolState String -> String-gvShowFinal aut stmap =- if isEmptyIntersect (concat $ states aut) fin- then ""- else "node [ peripheries = 2 ]; "- ++ concatMap (\x -> " " ++ lookupId x) fin- ++ "\n"- where fin = finalSt aut- lookupId x = Map.findWithDefault "error_final" x stmap-\end{code}--Each transition is displayed with the name of the tree. If there is more-than one transition to the same state, they are displayed on a single-label.--\begin{code}-gvShowTrans :: PolAut -> Map.Map PolState String- -> String -> PolState -> String-gvShowTrans aut stmap idFrom st =- let -- outgoing transition labels from st- trans = Map.findWithDefault Map.empty st $ transitions aut- -- returns the graphviz dot command to draw a labeled transition- drawTrans (stTo,x) = case Map.lookup stTo stmap of- Nothing -> drawTrans' ("id_error_" ++ (sem_ stTo)) x- Just idTo -> drawTrans' idTo x- where sem_ (PolSt i _ _) = show i- --showSem (PolSt (_,pred,_) _ _) = pred- drawTrans' idTo x = gvEdge idFrom idTo (drawLabel x) []- drawLabel labels = gvUnlines labs- where- lablen = length labels- maxlabs = 6- excess = "...and " ++ (show $ lablen - maxlabs) ++ " more"- --- labstrs = map fn labels- fn Nothing = "EMPTY"- fn (Just x) = idname x- --- labs = if lablen > maxlabs- then take maxlabs labstrs ++ [ excess ]- else labstrs- in unlines $ map drawTrans $ Map.toList trans-\end{code}--%gvShowTransPred te =-% let p = tpredictors te-% charge fv = case () of _ | c == -1 -> "-"-% | c == 1 -> "+"-% | c > 0 -> "+" ++ (show c)-% | otherwise -> (show c)-% where c = lookupWithDefaultFM p 0 fv-% showfv (f,v) = charge (f,v) ++ f-% ++ (if (null v) then "" else ":" ++ v)-% in map showfv $ Map.keys p-
− src/NLP/GenI/Gui.lhs
@@ -1,778 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.--\chapter{Graphical User Interface} --\begin{code}-{-# LANGUAGE FlexibleContexts #-}-module NLP.GenI.Gui(guiGeni) where-\end{code}--\ignore{-\begin{code}-import Graphics.UI.WX--import qualified Control.Monad as Monad -import qualified Data.Map as Map--import Data.IORef-import Data.List (isPrefixOf, nub, delete, findIndex)-import Data.Maybe ( fromMaybe )-import System.Directory -import System.Exit (exitWith, ExitCode(ExitSuccess))--import qualified NLP.GenI.Builder as B-import qualified NLP.GenI.BuilderGui as BG-import NLP.GenI.Geni- ( ProgState(..), ProgStateRef, combine, initGeni- , lemmaSentenceString, GeniResult(..), prettyResult- , loadEverything, loadTestSuite, loadTargetSemStr- , showRealisations )-import NLP.GenI.General (boundsCheck, geniBug, trim, fst3)-import NLP.GenI.Btypes (TestCase(..), showFlist,)-import NLP.GenI.Tags (idname, tpolarities, TagElem)-import NLP.GenI.GeniShow (geniShow)-import NLP.GenI.Configuration- ( Params(..), Instruction, hasOpt- , hasFlagP, deleteFlagP, setFlagP, getFlagP, getListFlagP- , parseFlagWithParsec- --- , ExtraPolaritiesFlg(..)- , LexiconFlg(..)- , MacrosFlg(..)- , MorphCmdFlg(..)- , MorphInfoFlg(..)- , OptimisationsFlg(..)- , RankingConstraintsFlg(..)- , RootFeatureFlg(..)- , TestSuiteFlg(..)- , TestInstructionsFlg(..)- , ViewCmdFlg(..)- --- , Optimisation(..)- , BuilderType(..), mainBuilderTypes )-import NLP.GenI.GeniParsers hiding ( choice, label, tab )-import NLP.GenI.GuiHelper--import NLP.GenI.Polarity-import NLP.GenI.Simple.SimpleGui-import NLP.GenI.Statistics (Statistics, showFinalStats)-\end{code}-}--\section{Main Gui}--\begin{code}-guiGeni :: ProgStateRef -> IO() -guiGeni pstRef = start $ mainGui pstRef-\end{code}--When you first start GenI, you will see this screen:--\begin{center}-\includegraphics[width=0.47\textwidth]{hcar/GenI-main-screenshot.jpg}-\end{center}--It allows you to type in an input semantics (or to modify the one that was-automatically loaded up), select some optimisations and run the realiser. You-can also opt to run the debugger instead of the realiser (section-\ref{sec:gui:debugger}).--\begin{code}-mainGui :: ProgStateRef -> IO ()-mainGui pstRef - = do --- pst <- readIORef pstRef- -- Top Window- f <- frame [text := "Geni Project"]- -- create statusbar field- status <- statusField []- -- create the file menu- fileMen <- menuPane [text := "&File"]- loadMenIt <- menuItem fileMen [text := "&Open files or configure GenI"]- quitMenIt <- menuQuit fileMen [text := "&Quit"]- set quitMenIt [on command := close f ]- -- create the tools menu- toolsMen <- menuPane [text := "&Tools"]- gbrowserMenIt <- menuItem toolsMen [ text := "&Inspect grammar" - , help := "Displays the trees in the grammar" ]- -- create the help menu- helpMen <- menuPane [text := "&Help"]- aboutMeIt <- menuAbout helpMen [help := "About"]- -- Tie the menu to this window- set f [ statusBar := [status] - , menuBar := [fileMen, toolsMen, helpMen]- -- put the menu event handler for an about box on the frame.- , on (menu aboutMeIt) := infoDialog f "About GenI" "The GenI generator.\nhttp://wiki.loria.fr/wiki/GenI" - -- event handler for the tree browser- , on (menu gbrowserMenIt) := do { loadEverything pstRef; treeBrowserGui pstRef } - ]- -- ------------------------------------------------------------------ -- buttons- -- ------------------------------------------------------------------ let config = pa pst - hasSem = hasFlagP TestSuiteFlg config- -- Target Semantics- testSuiteChoice <- choice f [ selection := 0, enabled := hasSem ]- tsTextBox <- textCtrl f [ wrap := WrapWord- , clientSize := sz 400 80- , enabled := hasSem - , text := "" ]- testCaseChoice <- choice f [ selection := 0 - , enabled := hasSem ]- -- Box and Frame for files loaded - macrosFileLabel <- staticText f [ text := getListFlagP MacrosFlg config ]- lexiconFileLabel <- staticText f [ text := getListFlagP LexiconFlg config ]- -- Generate and Debug - let genfn = doGenerate f pstRef tsTextBox- pauseOnLexChk <- checkBox f [ text := "Inspect lex", tooltip := "Affects debugger only" ]- debugBt <- button f [ text := "Debug"- , on command := get pauseOnLexChk checked >>= genfn True ]- genBt <- button f [text := "Generate", on command := genfn False False ]- quitBt <- button f [ text := "Quit",- on command := close f]- -- ------------------------------------------------------------------ -- optimisations- -- ------------------------------------------------------------------ algoChoiceBox <- radioBox f Vertical (map show mainBuilderTypes)- [ selection := case builderType config of- SimpleBuilder -> 0- SimpleOnePhaseBuilder -> 1- NullBuilder -> 0 ]- set algoChoiceBox [ on select := toggleAlgo pstRef algoChoiceBox ]- polChk <- optCheckBox Polarised pstRef f- [ text := "Polarities"- , tooltip := "Use the polarity optimisation"- ]- useSemConstraintsChk <- antiOptCheckBox NoConstraints pstRef f- [ text := "Sem constraints"- , tooltip := "Use any sem constraints the user provides"- ]- earlyNaChk <- optCheckBox EarlyNa pstRef f- [ text := "NA detection"- , tooltip := "Early detection of nodes that cannot be adjoined to"- ]- iafChk <- optCheckBox Iaf pstRef f- [ text := "Idx acc filter"- , tooltip := "Only available in CKY/Earley for now"- ]- semfilterChk <- optCheckBox SemFiltered pstRef f- [ text := "Semantic filters"- , tooltip := "(2p only) Filter away semantically incomplete structures before adjunction phase"- ]- extrapolText <- staticText f - [ text := maybe "" showLitePm $ getFlagP ExtraPolaritiesFlg config- , tooltip := "Use the following additional polarities" - ]- -- commands for the checkboxes- let togglePolStuff = do c <- get polChk checked- set extrapolText [ enabled := c ]- set polChk [on command :~ (>> togglePolStuff) ]- -- ------------------------------------------------------------------ -- layout; packing it all together- -- ------------------------------------------------------------------ -- set any last minute handlers, run any last minute functions- let onLoad = readConfig f pstRef macrosFileLabel lexiconFileLabel testSuiteChoice tsTextBox testCaseChoice- set loadMenIt [ on command := do configGui pstRef onLoad ]- onLoad- togglePolStuff- --- let labeledRow l w = row 1 [ label l, hfill (widget w) ]- let gramsemBox = boxed "Files last loaded" $ - hfill $ column 1 - [ labeledRow "trees:" macrosFileLabel- , labeledRow "lexicon:" lexiconFileLabel- ]- optimBox = --boxed "Optimisations " $ -- can't used boxed with wxwidgets 2.6 -- bug?- column 5 [ label "Algorithm"- , dynamic $ widget algoChoiceBox- , label "Optimisations"- , dynamic $ widget polChk - , row 5 [ label " ", column 5 - [ dynamic $ row 5 [ label "Extra: ", widget extrapolText ] ] ]- , dynamic $ widget useSemConstraintsChk- , dynamic $ widget semfilterChk - , dynamic $ widget earlyNaChk- , dynamic $ widget iafChk- ]- set f [layout := column 5 [ gramsemBox- , row 5 [ fill $ -- boxed "Input Semantics" $ - hfill $ column 5 - [ labeledRow "test suite: " testSuiteChoice- , labeledRow "test case: " testCaseChoice- , fill $ widget tsTextBox ]- , vfill optimBox ]- -- ----------------------------- Generate and quit - , row 1 [ widget quitBt - , hfloatRight $ row 5 [ widget pauseOnLexChk, widget debugBt, widget genBt ]] ]- , clientSize := sz 525 325- , on closing := exitWith ExitSuccess - ]---- Note the following point about anti-optimisations: An anti-optimisation--- disables a default behaviour which is assumed to be "optimisation". But of--- course we don't want to confuse the GUI user, so we confuse the programmer--- instead: Given an anti-optimisation DisableFoo, we have a check box UseFoo. If--- UseFoo is checked, we remove DisableFoo from the list; if it is unchecked, we--- add it to the list. This is the opposite of the default behaviour, but the--- result, I hope, is intuitive for the user.-toggleAlgo :: (Selection a, Items a String) => ProgStateRef -> a -> IO ()-toggleAlgo pstRef box =- do asel <- get box selection- aitems <- get box items- let selected = aitems !! asel- btable = zip (map show mainBuilderTypes) mainBuilderTypes- btype = case [ b | (name, b) <- btable, name == selected ] of- [] -> geniBug $ "Unknown builder type " ++ selected- [b] -> b- _ -> geniBug $ "More than one builder has the name " ++ selected- modifyIORef pstRef (\x -> x { pa = (pa x) { builderType = btype } })--optCheckBox, antiOptCheckBox ::- Optimisation -> ProgStateRef- -> Window a -> [Prop (CheckBox ())]- -> IO (CheckBox ())---- | Checkbox for enabling or disabling an optimisation--- You need not set the checked or on command attributes--- as this is done for you (but you can if you want,--- setting checked will override the default, and any--- command you set will be run before the toggle stuff)-optCheckBox = optCheckBoxHelper id---- | Same as 'optCheckBox' but for anti-optimisations-antiOptCheckBox = optCheckBoxHelper not--optCheckBoxHelper :: (Bool -> Bool) -> Optimisation -> ProgStateRef- -> Window a -> [Prop (CheckBox ())]- -> IO (CheckBox ())-optCheckBoxHelper idOrNot o pstRef f as =- do pst <- readIORef pstRef- chk <- checkBox f $ [ checked := idOrNot $ hasOpt o $ pa pst ] ++ as- set chk [ on command :~ (>> onCheck chk) ]- return chk- where- onCheck chk =- do isChecked <- get chk checked- pst <- readIORef pstRef- let config = pa pst- modopt = if idOrNot isChecked then (o:) else delete o- newopts = nub.modopt $ getListFlagP OptimisationsFlg config- modifyIORef pstRef (\x -> x{pa = setFlagP OptimisationsFlg newopts (pa x)})---- ----------------------------------------------------------------------- Loading files--- ------------------------------------------------------------------------ | 'readConfig' is used to update the graphical interface after--- you run the 'configGui'.--- It is also called when you first launch the GUI-readConfig :: (Textual l, Textual t, Able ch, Items ch String, Selection ch, Selecting ch)- => Window w -> ProgStateRef -> l -> l -> ch -> t -> ch -> IO ()-readConfig f pstRef macrosFileLabel lexiconFileLabel suiteChoice tsBox caseChoice =- do pst <- readIORef pstRef- let config = pa pst- -- errHandler title err = errorDialog f title (show err)- set macrosFileLabel [ text := getListFlagP MacrosFlg config ]- set lexiconFileLabel [ text := getListFlagP LexiconFlg config ]- -- set tsFileLabel [ text := getListFlagP TestSuiteFlg config ]- -- read the test suite if there is one- case getListFlagP TestInstructionsFlg config of- [] ->- do set suiteChoice [ enabled := False, items := [] ]- set caseChoice [ enabled := False, items := [] ]- is ->- do -- handler for selecting a test suite- let imap = Map.fromList $ zip [0..] is- onTestSuiteChoice = do- sel <- get suiteChoice selection- case Map.lookup sel imap of- Nothing -> geniBug $ "No such index in test suite selector (gui): " ++ show sel- Just t -> loadTestSuiteAndRefresh f pstRef t tsBox caseChoice- set suiteChoice [ enabled := True, items := map fst is- , on select := onTestSuiteChoice, selection := 0 ]- set caseChoice [ enabled := True ]- onTestSuiteChoice -- load the first suite---- | Load the given test suite and update the GUI accordingly.--- This is used when you first start the graphical interface--- or when you run the configuration menu.-loadTestSuiteAndRefresh :: (Textual a, Selecting b, Selection b, Items b String) - => Window w -> ProgStateRef -> Instruction -> a -> b -> IO ()-loadTestSuiteAndRefresh f pstRef (suitePath,mcs) tsBox caseChoice =- do (loadTestSuite pstRef >> return ())- `catch` \e -> errorDialog f ("Error reading test suite " ++ suitePath) (show e)- pst <- readIORef pstRef- let suite = tsuite pst- theCase = tcase pst- suiteCases = case filter (\c -> tcName c `elem` cs) suite of- [] -> suite- res -> res- where cs = fromMaybe [] mcs- suiteCaseNames = map tcName suiteCases- -- we number the cases for easy identification, putting - -- a star to highlight the selected test case (if available)- let numfn :: Int -> String -> String- numfn n t = (if t == theCase then "* " else "")- ++ (show n) ++ ". " ++ t- tcaseLabels = zipWith numfn [1..] suiteCaseNames- -- we select the first case in cases_, if available- caseSel <- if null theCase- then return 0- else case findIndex (== theCase) suiteCaseNames of- Nothing -> do errorDialog f "" ("No such test case: " ++ theCase)- return 0- Just i -> return i- ----------------------------------------------------- -- handler for selecting a test case- ----------------------------------------------------- let displaySemInput (TestCase { tcSem = si, tcSemString = str }) =- geniShow $ toSemInputString si str- let onTestCaseChoice = do- csel <- get caseChoice selection- if boundsCheck csel suite- then do let s = (suiteCases !! csel)- set tsBox [ text :~ (\_ -> displaySemInput s) ]- else geniBug $ "Gui: test case selector bounds check error: " ++- show csel ++ " of " ++ show tcaseLabels ++ "\n"- ----------------------------------------------------- set caseChoice [ items := tcaseLabels - , selection := caseSel- , on select := onTestCaseChoice ]- when (not $ null suite) onTestCaseChoice -- run this once-\end{code}- -% ---------------------------------------------------------------------\section{Configuration}-% ----------------------------------------------------------------------The configuration GUI aims to a provide a graphical substitute for the command-line switches. Note you cannot yet select optimisations and test cases from-this window; use the main window instead. Note also that changes to GenI tend-to start from the command line switches and only percolate to the GUI when time-permits. For full control of GenI, see \verb!geni --help!.--\begin{center}-\emph{TODO: screenshot wanted}-\end{center}--\begin{code}--- | 'configGui' @pstRef loadFn@ provides the configuration GUI. The continuation--- @loadFn@ tells us what to do when the user closes this window.-configGui :: ProgStateRef -> IO () -> IO () -configGui pstRef loadFn = do - pst <- readIORef pstRef- let config = pa pst- -- - f <- frame []- p <- panel f []- nb <- notebook p []- let browseTxt = "Browse"- --- let fakeBoxed title lst = hstretch $ column 3 $ map hfill $ - [ hrule 1 , alignRight $ label title, vspace 5 ] - ++ map hfill lst- let shortSize = sz 10 25- let longSize = sz 20 25- -- ------------------------------------------------------------------ -- basic options tab- -- ------------------------------------------------------------------ pbas <- panel nb []- -- files loaded (labels)- macrosFileLabel <- staticText pbas [ text := getListFlagP MacrosFlg config ]- lexiconFileLabel <- staticText pbas [ text := getListFlagP LexiconFlg config ]- tsFileLabel <- staticText pbas [ text := getListFlagP TestSuiteFlg config ]- -- "Browse buttons"- macrosBrowseBt <- button pbas [ text := browseTxt ]- lexiconBrowseBt <- button pbas [ text := browseTxt ]- tsBrowseBt <- button pbas [ text := browseTxt ]- -- root feature- rootFeatTxt <- entry pbas- [ text := showFlist $ getListFlagP RootFeatureFlg config- , size := longSize ]- let layFiles = [ row 1 [ label "trees:" - , fill $ widget macrosFileLabel- , widget macrosBrowseBt ]- , row 1 [ label "lexicon:"- , fill $ widget lexiconFileLabel- , widget lexiconBrowseBt ] - , row 1 [ label "test suite:"- , fill $ widget tsFileLabel- , widget tsBrowseBt ]- , hspace 5- , hfill $ vrule 1- , row 3 [ label "root features"- , hglue- , rigid $ widget rootFeatTxt ] - ] - -- the layout for the basic stuff- let layBasic = dynamic $ container pbas $ -- boxed "Basic options" $ - hfloatLeft $ dynamic $ fill $ column 4 $ map (dynamic.hfill) $ layFiles - -- ------------------------------------------------------------------ -- advanced options tab- -- ------------------------------------------------------------------ padv <- panel nb []- -- XMG tools - viewCmdTxt <- entry padv - [ tooltip := "Command used for XMG tree viewing"- , text := getListFlagP ViewCmdFlg config ]- let layXMG = fakeBoxed "XMG tools" - [ row 3 [ label "XMG view command"- , marginRight $ hfill $ widget viewCmdTxt ] ]- -- polarities- extraPolsTxt <- entry padv - [ text := maybe "" showLitePm $ getFlagP ExtraPolaritiesFlg config- , size := shortSize ]- let layPolarities = fakeBoxed "Polarities" [ hfill $ row 1 - [ label "extra polarities", rigid $ widget extraPolsTxt ] ]- -- morphology- morphFileLabel <- staticText padv [ text := getListFlagP MorphInfoFlg config ]- morphFileBrowseBt <- button padv [ text := browseTxt ]- morphCmdTxt <- entry padv - [ tooltip := "Commmand used for morphological generation" - , text := getListFlagP MorphCmdFlg config ]- let layMorph = fakeBoxed "Morphology" - [ row 3 [ label "morph info:"- , expand $ hfill $ widget morphFileLabel- , widget morphFileBrowseBt ]- , row 3 [ label "morph command"- , (marginRight.hfill) $ widget morphCmdTxt ] ]- -- put the whole darn thing together- let layAdvanced = hfloatLeft $ container padv $ column 10 - $ [ layXMG, layPolarities, layMorph]- -- ------------------------------------------------------------------ -- browse button action- --- -- When the user clicks on a Browse button, an open file dialogue should pop up.- -- It gets its value from the file label on its left (passed in as an argument),- -- and updates said label when the user has made a selection.- -- ------------------------------------------------------------------ -- helper functions- curDir <- getCurrentDirectory- let curDir2 = curDir ++ "/"- trim2 pth = if curDir2 `isPrefixOf` pth2- then drop (length curDir2) pth2- else pth2- where pth2 = trim pth- let onBrowse theLabel - = do rawFilename <- get theLabel text- let filename = trim2 rawFilename- filetypes = [("Any file",["*","*.*"])]- fsel <- fileOpenDialog f False True- "Choose your file..." filetypes "" filename- case fsel of- -- if the user does not select any file there are no changes- Nothing -> return () - Just file -> set theLabel [ text := trim2 file ]- -- end onBrowse- -- activate those "Browse" buttons- let setBrowse w l = set w [ on command := onBrowse l ]- setBrowse macrosBrowseBt macrosFileLabel- setBrowse lexiconBrowseBt lexiconFileLabel - setBrowse tsBrowseBt tsFileLabel- setBrowse morphFileBrowseBt morphFileLabel- -- ------------------------------------------------------------------ -- config GUI layout- -- ------------------------------------------------------------------ let parsePol = parseFlagWithParsec "polarities" geniPolarities- parseRF = parseFlagWithParsec "root features" geniFeats- onLoad - = do macrosVal <- get macrosFileLabel text- lexconVal <- get lexiconFileLabel text- tsVal <- get tsFileLabel text- --- rootCatVal <- get rootFeatTxt text- extraPolVal <- get extraPolsTxt text- --- viewVal <- get viewCmdTxt text - --- morphCmdVal <- get morphCmdTxt text- morphInfoVal <- get morphFileLabel text- --- let maybeSet fl fn x =- if null x then deleteFlagP fl else setFlagP fl (fn x)- maybeSetStr fl x = maybeSet fl id x- let setConfig = id- . (maybeSetStr MacrosFlg macrosVal)- . (maybeSetStr LexiconFlg lexconVal)- . (maybeSetStr TestSuiteFlg tsVal)- . (maybeSetStr TestInstructionsFlg [(tsVal,Nothing)])- . (maybeSet RootFeatureFlg parseRF rootCatVal)- . (maybeSet ExtraPolaritiesFlg parsePol extraPolVal)- . (maybeSetStr ViewCmdFlg viewVal)- . (maybeSetStr MorphCmdFlg morphCmdVal)- . (maybeSetStr MorphInfoFlg morphInfoVal)- modifyIORef pstRef $ \x -> x { pa = setConfig (pa x) }- loadFn - -- end onLoad- -- the button bar- cancelBt <- button p - [ text := "Cancel", on command := close f ]- loadBt <- button p - [ text := "Load", on command := do { onLoad; close f } ]- let layButtons = hfill $ row 1 - [ hfloatLeft $ widget cancelBt- , hfloatRight $ widget loadBt ]- --- set f [ layout := dynamic $ fill $ container p $ column 0 - [ fill $ tabs nb [ tab "Basic" layBasic- , tab "Advanced" layAdvanced ] - , hfill $ layButtons ]- ] -\end{code}- -% ---------------------------------------------------------------------\section{Generation}-% ----------------------------------------------------------------------\begin{code}--- | 'doGenerate' parses the target semantics, then calls the generator and--- displays the result in a results gui (below).-doGenerate :: Textual b => Window a -> ProgStateRef -> b -> Bool -> Bool -> IO ()-doGenerate f pstRef sembox useDebugger pauseOnLex =- do loadEverything pstRef- sem <- get sembox text- loadTargetSemStr pstRef sem- --- pst <- readIORef pstRef- let config = pa pst- withBuilderGui a =- case builderType config of- NullBuilder -> error "No gui available for NullBuilder"- SimpleBuilder -> a simpleGui_2p- SimpleOnePhaseBuilder -> a simpleGui_1p- --- let doDebugger bg = debugGui bg pstRef pauseOnLex- doResults bg = resultsGui bg pstRef- do catch (withBuilderGui $ if useDebugger then doDebugger else doResults)- (handler "Error during realisation")- -- FIXME: it would be nice to distinguish between generation and ts- -- parsing errors- `catch` (handler "Error parsing the input semantics")- where- handler title err = errorDialog f title (show err)-\end{code}--When surface realisation is complete, we display a results window with various-tabs for intermediary results in lexical selection, derived trees, derivation-trees and generation statistics.--\begin{center}-\emph{TODO: screenshot wanted}-\end{center}--\begin{code}-resultsGui :: BG.BuilderGui -> ProgStateRef -> IO ()-resultsGui builderGui pstRef =- do -- results window- f <- frame [ text := "Results"- , fullRepaintOnResize := False- , layout := stretch $ label "Generating..."- , clientSize := sz 300 300- ]- p <- panel f []- nb <- notebook p []- -- realisations tab- (results,stats,resTab) <- BG.resultsPnl builderGui pstRef nb- -- summary tab- let sentences = concatMap grRealisations results- summTab <- statsGui nb sentences stats- -- ranking tab- pst <- readIORef pstRef- let useRanking = hasFlagP RankingConstraintsFlg (pa pst)- rankTab <- messageGui nb . unlines . map (prettyResult pst) $ results- -- tabs- let myTabs = [ tab "summary" summTab- , tab "realisations" resTab- ] ++- (if useRanking then [ tab "ranking" rankTab ] else [])- -- pack it all together- set f [ layout := container p $ column 0 [ tabs nb myTabs ]- , clientSize := sz 700 600 ]- return ()---- | 'statsGui' displays the generation statistics and provides a--- handy button for saving results to a text file.-statsGui :: (Window a) -> [String] -> Statistics -> IO Layout-statsGui f sentences stats =- do let msg = showRealisations sentences- --- p <- panel f []- t <- textCtrl p [ text := msg, enabled := False ]- statsTxt <- staticText p [ text := showFinalStats stats ]- --- saveBt <- button p [ text := "Save to file"- , on command := maybeSaveAsFile f msg ]- return $ fill $ container p $ column 1 $- [ hfill $ label "Performance data"- , hfill $ widget statsTxt- , hfill $ label "Realisations"- , fill $ widget t- , hfloatRight $ widget saveBt ]-\end{code}--% ---------------------------------------------------------------------\section{Debugging}-\label{sec:gui:debugger}-% ----------------------------------------------------------------------Instead of going directly to the results window, you could instead use the-interactive debugger which GenI provides. The debugger shows a separate tab-for each phase in surface realisation (lexical selection, filtering, building).--\begin{center}-\includegraphics[width=0.47\textwidth]{hcar/GenI-debugger-screenshot.jpg}-\end{center}--\begin{code}--- | We provide here a universal debugging interface, which makes use of some--- parameterisable bits as defined in the BuilderGui module.-debugGui :: BG.BuilderGui -> ProgStateRef -> Bool -> IO ()-debugGui builderGui pstRef pauseOnLex =- do pst <- readIORef pstRef- let config = pa pst- btype = show $ builderType config- --- f <- frame [ text := "GenI Debugger - " ++ btype ++ " edition"- , fullRepaintOnResize := False- , clientSize := sz 300 300 ]- p <- panel f []- nb <- notebook p []- -- generation step 1- initStuff <- initGeni pstRef- let (cand,_) = unzip $ B.inCands initStuff- -- continuation for candidate selection tab- let step2 newCands =- do -- generation step 2.A (run polarity stuff)- let newInitStuff = initStuff { B.inCands = map (\x -> (x, -1)) newCands }- (input2, _, autstuff) = B.preInit newInitStuff config- -- automata tab- let (auts, _, finalaut, _) = autstuff- autPnl <- if hasOpt Polarised config- then fst3 `fmap` polarityGui nb auts finalaut- else messageGui nb "polarity filtering disabled"- -- generation step 2.B (start the generator for each path)- debugPnl <- BG.debuggerPnl builderGui nb config input2 btype- let autTab = tab "automata" autPnl- debugTab = tab (btype ++ "-session") debugPnl- genTabs = if hasOpt Polarised config- then [ autTab, debugTab ] else [ debugTab ]- --- set f [ layout := container p $ tabs nb genTabs- , clientSize := sz 700 600 ]- return ()- -- candidate selection tab- (canPnl,_,_) <- if pauseOnLex- then pauseOnLexGui pst nb cand step2- else candidateGui pst nb cand- -- basic tabs- let basicTabs = [ tab "lexical selection" canPnl ]- --- set f [ layout := container p $ tabs nb basicTabs- , clientSize := sz 700 600 ]- -- display all tabs if we are not told to pause on lex selection- when (not pauseOnLex) (step2 cand)-\end{code}--\subsection{Stepping through the debugger}--The interactive debugger can have a diffrent GUI for each realisation algorithm.-Here we will discuss the interface for the Simple 2-Phase algorithm which \geni-uses by default. The interfaces for other algorithms are likely to very similar.--\begin{center}-\includegraphics[width=0.47\textwidth]{images/debugger-features.png}-\end{center}--The debugger allows you to step through chart generation. Using the 'Step by'-button, you can walk through an arbitrary number of steps, where each step-consists in pulling one item of the agenda, combining it with the chart and-putting some of the results back on to the agenda (or the trash, or results-pile as the case may be). New chart items produced on each step typically have-one of their nodes highlighted in red. This indicates that the node was the-site of the most recent ``event''. For example in the substitution phase, the-red node indicates where the substitution operation was performed; whereas in-the adjunction phase, it could either indicate where adjunction was performed-or where a null-adjunction constraint was applied.--If you select the ``show features'' checkbox, all nodes in the chart item will-be expanded to reveal the underlying feature structures. The components of this-expanded representation are segmented into the following boxes:--\vspace{1em}-\begin{tabular}{ll}-\begin{minipage}{0.10\textwidth}-\includegraphics[width=\textwidth]{images/debugger-features-focus.png}-\end{minipage} &-\begin{minipage}{0.70\textwidth}-\begin{enumerate}-\item Summary: here, \verb!n:j.m! indicates that the category is \verb!n!,- that the top \verb!idx! feature is associated with \verb'j' and the- bottom one with \verb!m!.-\item Decorations: here, $\downarrow$ indicates that this is a TAG substitution- node, following the usual conventions in the literature.-\item The top feature structure-\item The bottom feature structure-\end{enumerate}-\end{minipage} \\-\end{tabular}--% ---------------------------------------------------------------------\section{Tree browser}-\label{sec:treebrowser_gui}-% ----------------------------------------------------------------------The GenI tree browser displays all the TAG trees in the grammar grouped-according to the semantics with which they are associated.--\begin{code}--- Note that we can't just reuse candidateGui's code because we label and sort--- the trees differently. Here we ignore the arguments in tree semantics, and--- we display the tree polarities in its label.-treeBrowserGui :: ProgStateRef -> IO () -treeBrowserGui pstRef = do- pst <- readIORef pstRef- -- ALL THE TREES in the grammar... muahahaha!- let semmap = combine (gr pst) (le pst)- -- browser window- f <- frame [ text := "Tree Browser" - , fullRepaintOnResize := False - ] - -- the heavy GUI artillery- let sem = Map.keys semmap- --- lookupTr k = Map.findWithDefault [] k semmap- treesfor k = Nothing : (map Just $ lookupTr k)- labsfor k = ("___" ++ k ++ "___") : (map fn $ lookupTr k)- where fn t = idname t ++ polfn (tpolarities t)- polfn p = if Map.null p - then "" - else " (" ++ showLitePm p ++ ")"- --- trees = concatMap treesfor sem- itNlabl = zip trees (concatMap labsfor sem)- (browser,_,_) <- tagViewerGui pst f "tree browser" "grambrowser" itNlabl- -- the button panel- let count = length trees - length sem- quitBt <- button f [ text := "Close", on command := close f ]- -- pack it all together - set f [ layout := column 5 [ browser, - row 5 [ label ("number of trees: " ++ show count)- , hfloatRight $ widget quitBt ] ]- , clientSize := sz 700 600 ]- return ()-\end{code}
− src/NLP/GenI/GuiHelper.hs
@@ -1,750 +0,0 @@--- GenI surface realiser--- Copyright (C) 2005 Carlos Areces and Eric Kow------ This program is free software; you can redistribute it and/or--- modify it under the terms of the GNU General Public License--- as published by the Free Software Foundation; either version 2--- of the License, or (at your option) any later version.------ This program is distributed in the hope that it will be useful,--- but WITHOUT ANY WARRANTY; without even the implied warranty of--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the--- GNU General Public License for more details.------ You should have received a copy of the GNU General Public License--- along with this program; if not, write to the Free Software--- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.--{-# LANGUAGE FlexibleContexts #-}-module NLP.GenI.GuiHelper where--import Graphics.UI.WX--- import Graphics.UI.WXCore--import Control.Arrow ( (&&&), (***) )-import qualified Control.Monad as Monad -import Control.Monad.State.Strict ( execStateT, runState )-import qualified Data.Map as Map--import Data.IORef-import System.Directory -import System.FilePath ((<.>),(</>),dropExtensions)-import System.Process (runProcess)-import Text.ParserCombinators.Parsec (parseFromFile)--import NLP.GenI.Graphviz-import NLP.GenI.Automaton (numStates, numTransitions)--import NLP.GenI.Configuration ( getFlagP, MacrosFlg(..), ViewCmdFlg(..) )-import NLP.GenI.GeniShow(geniShow)-import NLP.GenI.GraphvizShow ()-import NLP.GenI.Tags (TagItem(tgIdName), tagLeaves)-import NLP.GenI.Geni- ( ProgState(..) )-import NLP.GenI.GeniParsers ( geniTagElems )-import NLP.GenI.General- (geniBug, boundsCheck, dropTillIncluding, ePutStrLn)-import NLP.GenI.Btypes- ( showAv, showPred, showLexeme, )-import NLP.GenI.PolarityTypes ( PolarityKey(..) )-import NLP.GenI.Tags- ( idname, mapBySem, TagElem(ttrace, tinterface) )--import NLP.GenI.Configuration- ( Params(..), MetricsFlg(..), setFlagP )--import qualified NLP.GenI.Builder as B-import NLP.GenI.Builder (queryCounter, num_iterations, chart_size,- num_comparisons)-import NLP.GenI.Polarity (PolAut, detectPolFeatures)-import NLP.GenI.GraphvizShowPolarity ()---- ------------------------------------------------------------------------- Types--- ------------------------------------------------------------------------data GraphvizStatus = GvError String- | GvNoSuchItem Int- | GvCached- | GvCreated FilePath- deriving Show---- ------------------------------------------------------------------------- Lexically selected items--- -------------------------------------------------------------------------- | 'candidateGui' displays the lexically selected items, grouped by the--- semantics they subsume.-candidateGui :: ProgState- -> Window a- -> [TagElem]- -> GvIO () Bool (Maybe TagElem)-candidateGui pst f xs = do- p <- panel f [] - (tb,gvRef,updater) <- tagViewerGui pst p "lexically selected item" "candidates"- $ sectionsBySem xs- let polFeats = "Polarity attributes detected: " ++ (unwords.detectPolFeatures) xs- warning = unlines $ filter (not.null) (polFeats : warnings pst)- -- side panel- sidePnl <- panel p []- ifaceLst <- singleListBox sidePnl [ tooltip := "interface for this tree (double-click me!)" ]- traceLst <- singleListBox sidePnl [ tooltip := "trace for this tree (double-click me!)" ]- tNoted <- textCtrl sidePnl [ wrap := WrapWord, text := "Hint: copy from below and paste into the sem:\n" ]- let laySide = container sidePnl $ column 2- [ label "interface"- , fill $ widget ifaceLst- , label "trace"- , fill $ widget traceLst- , label "notes"- , fill $ widget tNoted ]- -- handlers- let addLine :: String -> String -> String- addLine x y = y ++ "\n" ++ x- --- addToNoted w =- do sel <- get w selection- things <- get w items- when (sel > 0) $ set tNoted [ text :~ addLine (things !! sel) ]- set ifaceLst [ on doubleClick := \_ -> addToNoted ifaceLst ]- set traceLst [ on doubleClick := \_ -> addToNoted traceLst ]- -- updaters : what happens when the user selects an item- let updateTrace = gvOnSelect (return ())- (\s -> set traceLst [ items := ttrace s ])- updateIface = gvOnSelect (return ())- (\s -> set ifaceLst [ items := map showAv $ tinterface s ])- Monad.unless (null xs) $ do- addGvHandler gvRef updateTrace- addGvHandler gvRef updateIface- -- first time run- gvSt <- readIORef gvRef- updateIface gvSt- updateTrace gvSt- --- let layMain = fill $ row 2 [ fill tb, vfill laySide ]- theItems = if null warning then [ layMain ] else [ hfill (label warning) , layMain ]- lay = fill $ container p $ column 5 theItems- return (lay, gvRef, updater)--sectionsBySem :: (TagItem t) => [t] -> [ (Maybe t, String) ]-sectionsBySem tsem =- let semmap = mapBySem tsem- sem = Map.keys semmap- --- lookupTr k = Map.findWithDefault [] k semmap- section k = (Nothing, header) : (map tlab $ lookupTr k)- where header = "___" ++ showPred k ++ "___"- tlab t = (Just t, tgIdName t)- in concatMap section sem---- ------------------------------------------------------------------------- Polarity Automata--- -------------------------------------------------------------------------- | A browser to see the automata constructed during the polarity optimisation--- step.-polarityGui :: (Window a) -> [(PolarityKey,PolAut,PolAut)] -> PolAut- -> GvIO () () PolAut-polarityGui f xs final = do- let stats a = " (" ++ (show $ numStates a) ++ "st " ++ (show $ numTransitions a) ++ "tr)"- aut2 (_ , a1, a2) = [ a1, a2 ]- autLabel (PolarityKey fv,a1,a2) = [ fv ++ stats a1, fv ++ " pruned" ++ stats a2]- finalAutLab = ( final, "final" ++ stats final )- autslabs = concatBoth (map (aut2 &&& autLabel) xs) ++ [ finalAutLab ]- gvRef <- newGvRef () () "automata"- setGvDrawables gvRef autslabs- graphvizGui f "polarity" gvRef--concatBoth :: [ ([a],[b]) ] -> [ (a,b) ]-concatBoth = uncurry zip . (concat *** concat) . unzip -- is there a simpler way?---- ------------------------------------------------------------------------- Helpers--- ----------------------------------------------------------------------- --- | Any data structure which has corresponds to a TAG tree and which--- has some notion of derivation-class XMGDerivation a where- getSourceTrees :: a -> [String]--instance XMGDerivation TagElem where- getSourceTrees te = [idname te]---- | 'toSentence' almost displays a 'TagElem' as a sentence, but only good--- enough for debugging needs. The problem is that each leaf may be--- an atomic disjunction. Our solution is just to display each choice and--- use some delimiter to seperate them. We also do not do any--- morphological processing.-toSentence :: TagElem -> String-toSentence = unwords . map squishLeaf . tagLeaves--squishLeaf :: (a,([String], b)) -> String-squishLeaf = showLexeme.fst.snd---- ------------------------------------------------------------------------- TAG viewer--- -------------------------------------------------------------------------- | Variant of 'graphvizGui' with a toggle to view feature structures-tagViewerGui :: (GraphvizShow Bool t, TagItem t, XMGDerivation t)- => ProgState -> (Window a) -> String -> String -> [(Maybe t,String)]- -> GvIO () Bool (Maybe t)-tagViewerGui pst f tip cachedir itNlab = do- p <- panel f [] - gvRef <- newGvRef () False tip- setGvDrawables gvRef itNlab- (lay,ref,onUpdate) <- graphvizGui p cachedir gvRef- -- button bar widgets- detailsChk <- checkBox p [ text := "Show features"- , checked := False ]- viewTagLay <- viewTagWidgets p gvRef (pa pst)- -- handlers- let onDetailsChk =- do isDetailed <- get detailsChk checked- setGvParams gvRef isDetailed- onUpdate- set detailsChk [ on command := onDetailsChk ]- -- pack it all in - let cmdBar = hfill $ row 5 - [ dynamic $ widget detailsChk- , viewTagLay ]- lay2 = fill $ container p $ column 5 [ fill lay, cmdBar ]- return (lay2,ref,onUpdate)---- ------------------------------------------------------------------------- XMG Metagrammar stuff.--- See <http://sourcesup.cru.fr/xmg/>--- -------------------------------------------------------------------------- | Calls Yannick Parmentier's handy visualisation tool ViewTAG.-viewTagWidgets :: (GraphvizShow Bool t, TagItem t, XMGDerivation t)- => Window a -> GraphvizGuiRef st (Maybe t) Bool -> Params- -> IO Layout-viewTagWidgets p gvRef config =- do viewTagBtn <- button p [ text := "ViewTAG" ]- viewTagCom <- choice p [ tooltip := "derivation tree" ]- -- handlers- let onViewTag = readIORef gvRef >>=- gvOnSelect (return ())- (\t -> do let derv = getSourceTrees t- ds <- get viewTagCom selection- if boundsCheck ds derv- then runViewTag config (derv !! ds)- else geniBug $ "Gui: bounds check in onViewTag"- )- set viewTagBtn [ on command := onViewTag ]- -- when the user selects a tree, we want to update the list of derivations- let updateDerivationList = gvOnSelect- (set viewTagCom [ enabled := False ])- (\s -> set viewTagCom [ enabled := True- , items := getSourceTrees s- , selection := 0] )- addGvHandler gvRef updateDerivationList- updateDerivationList =<< readIORef gvRef- --- return $ row 5 $ map dynamic [ widget viewTagCom, widget viewTagBtn ]--runViewTag :: Params -> String -> IO ()-runViewTag params drName =- case getFlagP MacrosFlg params of- Nothing -> ePutStrLn "Warning: No macros files specified (runViewTag)"- Just f -> do- -- figure out what grammar file to use- let gramfile = dropExtensions f <.> "rec"- treenameOnly = takeWhile (/= ':') . dropTillIncluding ':' . dropTillIncluding ':'- -- run the viewer- case getFlagP ViewCmdFlg params of- Nothing -> ePutStrLn "Warning: No viewcmd specified (runViewTag)"- Just c -> do -- run the viewer- runProcess c [gramfile, treenameOnly drName]- Nothing Nothing Nothing Nothing Nothing- return ()---- ----------------------------------------------------------------------- Graphical debugger (helper functions)--- ------------------------------------------------------------------------ | 'pauseOnLexGui' allows the user to see lexical selection only and either--- dump it to file or read replace it by the contents of some other file-pauseOnLexGui :: ProgState -> (Window a) -> [TagElem]- -> ([TagElem] -> IO ()) -- ^ continuation- -> GvIO () Bool (Maybe TagElem)-pauseOnLexGui pst f xs job = do- p <- panel f []- candV <- varCreate xs- (tb, ref, updater) <- candidateGui pst p xs- -- supplementary button bar- let saveCmd =- do c <- varGet candV- let cStr = unlines $ map geniShow c- maybeSaveAsFile f cStr- loadCmd =- do let filetypes = [("Any file",["*","*.*"])]- fsel <- fileOpenDialog f False True "Choose your file..." filetypes "" ""- case fsel of- Nothing -> return ()- Just file ->- do parsed <- parseFromFile geniTagElems file- case parsed of- Left err -> errorDialog f "" (show err)- Right c -> do varSet candV c- setGvDrawables ref (sectionsBySem c)- updater- --- saveBt <- button p [ text := "Save to file", on command := saveCmd ]- loadBt <- button p [ text := "Load from file", on command := loadCmd ]- nextBt <- button p [ text := "Begin" ]- let disableW w = set w [ enabled := False ]- set nextBt [ on command := do mapM disableW [ saveBt, loadBt, nextBt ]- varGet candV >>= job ]- --- let lay = fill $ container p $ column 5- [ fill tb, hfill (vrule 1)- , row 0 [ row 5 [ widget saveBt, widget loadBt ]- , hfloatRight $ widget nextBt ] ]- return (lay, ref, updater)--type DebuggerItemBar st flg itm- = Panel () -- ^ parent panel- -> GraphvizGuiRef st (Maybe itm) flg -- ^ gv ref to use- -> GvUpdater -- ^ onUpdate- -> IO (Layout, GvUpdater)---- | A generic graphical debugger widget for GenI, including------ * item viewer which allows the user to select one of the items in the--- builder state.------ * item bar which provides some options on how to view the currently--- selected item, for example, if you want to display the features or not.------ * A dashboard which lets the user do things like ``go ahead 6 steps''.--- --- Besides the Builder, there are two functions you need to pass in make this--- work: ------ 1. a 'stateToGv' which converts the builder state into a list of items--- and labels the way 'graphvizGui' likes it------ 2. an 'item bar' function which lets you control what bits you display--- of a selected item (for example, if you want a detailed view or not)--- the item bar should return a layout ------ Note that we don't constrain the type of item returned by the builder to--- be the same as the type handled by your gui: that's quite normal because--- you might want to decorate the type with some other information-debuggerPanel :: (GraphvizShow flg itm) - => B.Builder st itm2 Params -- ^ builder to use- -> flg -- ^ initial value for the flag argument in GraphvizShow- -> (st -> [(Maybe itm, String)])- -- ^ function to convert a Builder state into lists of items- -- and their labels, the way graphvizGui likes it- -> (DebuggerItemBar st flg itm)- -- ^ 'itemBar' function returning a control panel configuring- -- how you want the currently selected item in the debugger- -- to be displayed- -> (Window a) -- ^ parent window- -> Params -- ^ geni params- -> B.Input -- ^ builder input- -> String -- ^ graphviz cache directory- -> IO Layout -debuggerPanel builder gvInitial stateToGv itemBar f config input cachedir = - do let initBuilder = B.init builder - nextStep = B.step builder - allSteps = B.stepAll builder - --- let (initS, initStats) = initBuilder input config2- config2 = setFlagP MetricsFlg (B.defaultMetricNames) config- p <- panel f [] - -- ---------------------------------------------------------- -- item viewer: select and display an item- -- ---------------------------------------------------------- gvRef <- newGvRef initS gvInitial "debugger session"- setGvDrawables gvRef (stateToGv initS)- (layItemViewer,_,onUpdateMain) <- graphvizGui p cachedir gvRef- -- ----------------------------------------------------------- -- item bar: controls for how an individual item is displayed- -- ----------------------------------------------------------- (layItemBar,onUpdateItemBar) <- itemBar p gvRef onUpdateMain- -- ------------------------------------------- - -- dashboard: controls for the debugger itself - -- ------------------------------------------- - let onUpdate = onUpdateMain >> onUpdateItemBar- db <- panel p []- restartBt <- button db [text := "Start over"]- nextBt <- button db [text := "Step by..."]- leapVal <- entry db [ text := "1", clientSize := sz 30 25 ]- finishBt <- button db [text := "Leap to end"]- statsTxt <- staticText db []- -- dashboard commands- let showQuery c gs = case queryCounter c gs of- Nothing -> "???"- Just q -> show q- updateStatsTxt gs = set statsTxt [ text :~ (\_ -> txtStats gs) ]- txtStats gs = unwords [ "itr", showQuery num_iterations gs- , "chart sz", showQuery chart_size gs- ]- ++ "\ncomparisons: " ++ showQuery num_comparisons gs- let genStep _ (st,stats) = runState (execStateT nextStep st) stats- let showNext s_stats = - do leapTxt <- get leapVal text- let leapInt :: Integer- leapInt = read leapTxt- (s2,stats2) = foldr genStep s_stats [1..leapInt]- modifyIORef gvRef $ \g -> g { gvcore = s2 }- setGvDrawables gvRef (stateToGv s2)- setGvSel gvRef 1- onUpdate- updateStatsTxt stats2- set nextBt [ on command :~ (\_ -> showNext (s2,stats2) ) ]- let showLast = - do -- redo generation from scratch- let (s2, stats2) = runState (execStateT allSteps initS) initStats - setGvDrawables gvRef (stateToGv s2)- onUpdate- updateStatsTxt stats2- let showReset = - do set nextBt [ on command := showNext (initS, initStats) ]- updateStatsTxt initStats - setGvDrawables gvRef (stateToGv initS)- setGvSel gvRef 1- onUpdate- -- dashboard handlers- set finishBt [ on command := showLast ]- set restartBt [ on command := showReset ]- showReset- -- dashboard layout - let layCmdBar = hfill $ container db $ row 5- [ widget statsTxt, hfloatRight $ row 5 - [ widget restartBt, widget nextBt - , widget leapVal, label " step(s)"- , widget finishBt ] ]- -- ------------------------------------------- - -- overall layout- -- ------------------------------------------- - return $ fill $ container p $ column 5 [ layItemViewer, layItemBar, hfill (vrule 1), layCmdBar ] ---- ----------------------------------------------------------------------- Graphviz GUI--- -----------------------------------------------------------------------data GraphvizOrder = GvoParams | GvoItems | GvoSel - deriving Eq--data GraphvizGuiSt st a b =- GvSt { gvcore :: st,- gvitems :: Map.Map Int a,- gvparams :: b,- gvlabels :: [String],- -- | tooltip for the selection box- gvtip :: String,- -- | handler function to call when the selection is- -- updated (note: before displaying the object)- gvhandler :: Maybe (GraphvizGuiSt st a b -> IO ()),- gvsel :: Int,- gvorders :: [GraphvizOrder] }---- | This provides a mechanism for communicating with the GUI. The basic idea:------ 1. you create a GvRef with newGvRef------ 2. you call 'graphvizGui' and get back an updater function------ 3. whenever you want to modify something, you use setGvWhatever and call--- the updater function------ 4. if you want to react to the selection being changed, you should set--- gvhandler-type GraphvizGuiRef st a b = IORef (GraphvizGuiSt st a b)--newGvRef :: st -> b -> String -> IO (GraphvizGuiRef st a b)-newGvRef initSt p t =- let st = GvSt { gvcore = initSt,- gvparams = p,- gvitems = Map.empty,- gvlabels = [], - gvhandler = Nothing,- gvtip = t,- gvsel = 0,- gvorders = [] }- in newIORef st--setGvSel :: GraphvizGuiRef st a b -> Int -> IO ()-setGvSel gvref s =- do let fn x = x { gvsel = s,- gvorders = GvoSel : (gvorders x) }- modifyIORef gvref fn - -setGvParams :: GraphvizGuiRef st a b -> b -> IO ()-setGvParams gvref c =- do let fn x = x { gvparams = c,- gvorders = GvoParams : (gvorders x) }- modifyIORef gvref fn --modifyGvParams :: GraphvizGuiRef st a b -> (b -> b) -> IO ()-modifyGvParams gvref fn =- do gvSt <- readIORef gvref- setGvParams gvref (fn $ gvparams gvSt)--setGvDrawables :: GraphvizGuiRef st a b -> [(a,String)] -> IO ()-setGvDrawables gvref itlb =- do let (it,lb) = unzip itlb- fn x = x { gvitems = Map.fromList $ zip [0..] it- , gvlabels = lb- , gvorders = GvoItems : (gvorders x)- }- modifyIORef gvref fn ---- | Helper function for making selection handlers (see 'addGvHandler')--- Note that this was designed for cases where the contents is a Maybe-gvOnSelect :: IO () -> (a -> IO ()) -> GraphvizGuiSt st (Maybe a) b -> IO ()-gvOnSelect onNothing onJust gvSt =- let sel = gvsel gvSt- things = gvitems gvSt- in case Map.lookup sel things of- Just (Just s) -> onJust s- _ -> onNothing--setGvHandler :: GraphvizGuiRef st a b -> Maybe (GraphvizGuiSt st a b -> IO ()) -> IO ()-setGvHandler gvref mh =- do gvSt <- readIORef gvref- modifyIORef gvref (\x -> x { gvhandler = mh })- case mh of - Nothing -> return ()- Just fn -> fn gvSt---- | add a selection handler - if there already is a handler--- this handler will be called before the new one-addGvHandler :: GraphvizGuiRef st a b -> (GraphvizGuiSt st a b -> IO ()) -> IO ()-addGvHandler gvref h =- do gvSt <- readIORef gvref- let newH = case gvhandler gvSt of - Nothing -> Just h- Just oldH -> Just (\g -> oldH g >> h g)- setGvHandler gvref newH--type GvIO st f d = IO (Layout, GraphvizGuiRef st d f, GvUpdater)-type GvUpdater = IO ()---- |'graphvizGui' @f glab cachedir gvRef@ is a general-purpose GUI for--- displaying a list of items graphically via AT&T's excellent Graphviz--- utility. We have a list box where we display all the labels the user--- provided. If the user selects an entry from this box, then the item--- corresponding to that label will be displayed.------ This returns a layout (wxhaskell container) and a function that you're--- expected to call whever something changes that would require the GUI to--- refresh itself (for example, you create a new chart item)------ * @f@ - (parent window) the GUI is provided as a panel within the parent.--- Note: we use window in the WxWidget's sense, meaning it could be--- anything as simple as a another panel, or a notebook tab.--- * @glab@ - (gui labels) a tuple of strings (tooltip, next button text)--- * @cachedir@ - the cache subdirectory. We intialise this by creating a cache--- directory for images which will be generated from the results--- * @gvRef@ - see above-graphvizGui :: (GraphvizShow f d) => (Window a) -> String -> GraphvizGuiRef st d f -> GvIO st f d-graphvizGui f cachedir gvRef = do- initGvSt <- readIORef gvRef- -- widgets- p <- panel f [ fullRepaintOnResize := False ]- split <- splitterWindow p []- (dtBitmap,sw) <- scrolledBitmap split - rchoice <- singleListBox split [tooltip := gvtip initGvSt]- -- set handlers- let openFn = openImage sw dtBitmap - -- pack it all together- let lay = fill $ container p $ margin 1 $ fill $ - vsplit split 5 200 (widget rchoice) (widget sw) - set p [ on closing := closeImage dtBitmap ]- ------------------------------------------------- -- create an updater function- ------------------------------------------------- let withoutSelector job =- bracket ( swap rchoice (on select) (return ()) )- ( \fn -> set rchoice [ on select := fn ] )- ( const job )- -- the selector calls onUpdate which calls the selector- -- indirectly by setting the selection- let onUpdate = withoutSelector $ do- gvSt <- readIORef gvRef- let orders = gvorders gvSt- initCacheDir cachedir- Monad.when (GvoItems `elem` orders) $- set rchoice [ items := gvlabels gvSt ]- Monad.when (GvoSel `elem` orders) $- set rchoice [ selection := gvsel gvSt ]- modifyIORef gvRef (\x -> x { gvorders = []})- createAndOpenImage cachedir p gvRef openFn- ------------------------------------------------- -- enable the tree selector- -- FIXME: not sure that this is correct- ------------------------------------------------- let selectAndShow = do- -- putStrLn "selectAndShow called" - sel <- get rchoice selection- -- note: do not use setGvSel (infinite loop)- modifyIORef gvRef (\x -> x { gvsel = sel })- -- call the handler if there is one - gvSt <- readIORef gvRef- case (gvhandler gvSt) of - Nothing -> return ()- Just h -> h gvSt- -- now do the update- onUpdate- ------------------------------------------------- set rchoice [ on select := selectAndShow ]- -- call the updater function for the first time- setGvSel gvRef 1- onUpdate - -- return the layout, the gvRef, and an updater function- -- The gvRef is to make it easier for users to muck around with the- -- state of the gui. Here, it's trivial, but when people combine guis- -- together, it might be easier to keep track of when returned- return (lay, gvRef, onUpdate)---- ---------------------------------------------------------------------- --- Bitmap stuff--- ---------------------------------------------------------------------- ---- | Bitmap with a scrollbar-scrolledBitmap :: Window a -> IO(VarBitmap, ScrolledWindow ())-scrolledBitmap p = do- dtBitmap <- variable [value := Nothing]- sw <- scrolledWindow p [scrollRate := sz 10 10, bgcolor := white,- on paint := onPaint dtBitmap,- fullRepaintOnResize := False ] - return (dtBitmap, sw)--type OpenImageFn = FilePath -> IO ()-type VarBitmap = Var (Maybe (Bitmap ())) --openImage :: Window a -> VarBitmap -> OpenImageFn-openImage sw vbitmap fname = do - -- load the new bitmap- bm <- bitmapCreateFromFile fname -- can fail with exception- closeImage vbitmap- set vbitmap [value := Just bm]- -- reset the scrollbars - bmsize <- get bm size - set sw [virtualSize := bmsize]- repaint sw- `catch` \_ -> repaint sw--closeImage :: VarBitmap -> IO ()-closeImage vbitmap = do - mbBitmap <- swap vbitmap value Nothing- case mbBitmap of- Nothing -> return ()- Just bm -> objectDelete bm--onPaint :: VarBitmap -> DC a -> b -> IO ()-onPaint vbitmap dc _ = do - mbBitmap <- get vbitmap value- case mbBitmap of- Nothing -> return () - Just bm -> do dcClear dc- drawBitmap dc bm pointZero False []---- | 'createAndOpenImage' attempts to draw an image (or retrieve it from cache)--- and opens it if we succeed. Otherwise, it does nothing at all; the creation--- function will display an error message if it fails.-createAndOpenImage :: (GraphvizShow f b) => - FilePath -> Window a -> GraphvizGuiRef st b f -> OpenImageFn -> IO ()-createAndOpenImage cachedir f gvref openFn = do - let errormsg g = "The file " ++ g ++ " was not created!\n"- ++ "Is graphviz installed?"- gvStatus <- createImage cachedir f gvref- case gvStatus of- GvCreated graphic ->- do exists <- doesFileExist graphic- if exists- then openFn graphic- else errorDialog f "" (errormsg graphic)- GvError err -> errorDialog f "" err- GvNoSuchItem _ -> return ()- GvCached -> return ()---- | Creates a graphical visualisation for anything which can be displayed--- by graphviz.-createImage :: (GraphvizShow f b)- => FilePath -- ^ cache directory- -> Window a -- ^ parent window- -> GraphvizGuiRef st b f -- ^ stuff to display- -> IO GraphvizStatus-createImage cachedir f gvref = do- gvSt <- readIORef gvref- -- putStrLn $ "creating image via graphviz"- let drawables = gvitems gvSt- sel = gvsel gvSt- config = gvparams gvSt- dotFile <- createDotPath cachedir (show sel)- graphicFile <- createImagePath cachedir (show sel)- let create x = do toGraphviz config x dotFile graphicFile- return . GvCreated $ graphicFile- handler err = do errorDialog f "Error calling graphviz" (show err) - return . GvError . show $ err- exists <- doesFileExist graphicFile- -- we only call graphviz if the image is not in the cache- if exists- then return (GvCreated graphicFile)- else case Map.lookup sel drawables of- Nothing -> return . GvNoSuchItem $ sel- Just it -> create it `catch` handler---- | Directory to dump image files in so that we can avoid regenerating them.--- If the directory already exists, we can just delete all the files in it.-initCacheDir :: String -> IO()-initCacheDir cachesubdir = do - mainCacheDir <- gv_CACHEDIR- cmainExists <- doesDirectoryExist mainCacheDir - Monad.when (not cmainExists) $ createDirectory mainCacheDir - -- - let cachedir = mainCacheDir </> cachesubdir- cExists <- doesDirectoryExist cachedir- if (cExists)- then do let notdot x = (x /= "." && x /= "..")- contents <- getDirectoryContents cachedir- olddir <- getCurrentDirectory- setCurrentDirectory cachedir- mapM removeFile $ filter notdot contents- setCurrentDirectory olddir- return ()- else createDirectory cachedir---- ------------------------------------------------------------------------- Miscellaneous--- -------------------------------------------------------------------------- | Save the given string to a file, if the user selets one via the file save--- dialog. Otherwise, don't do anything.-maybeSaveAsFile :: (Window a) -> String -> IO ()-maybeSaveAsFile f msg =- do let filetypes = [("Any file",["*","*.*"])]- fsel <- fileSaveDialog f False True "Save to" filetypes "" ""- case fsel of- Nothing -> return ()- Just file -> writeFile file msg---- | A message panel for use by the Results gui panels.-messageGui :: (Window a) -> String -> IO Layout -messageGui f msg = do - p <- panel f []- -- sw <- scrolledWindow p [scrollRate := sz 10 10 ]- t <- textCtrl p [ text := msg, enabled := False ]- return (fill $ container p $ column 1 $ [ fill $ widget t ]) --gv_CACHEDIR :: IO String-gv_CACHEDIR = do- home <- getHomeDirectory- return $ home </> ".gvcache"--createImagePath :: String -> String -> IO String-createImagePath subdir name = do- cdir <- gv_CACHEDIR- return $ cdir </> subdir </> name <.> "png"--createDotPath :: String -> String -> IO String-createDotPath subdir name = do - cdir <- gv_CACHEDIR- return $ cdir </> subdir </> name <.> "dot"
+ src/NLP/GenI/LexicalSelection.hs view
@@ -0,0 +1,425 @@+-- GenI surface realiser+-- Copyright (C) 2005 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++-- | This module performs the core of lexical selection and anchoring.+{-# LANGUAGE OverloadedStrings #-}+module NLP.GenI.LexicalSelection+where++import Control.Applicative ( (<$>) )+import Control.Arrow ((***))+import Control.Monad.Maybe+import Control.Monad.Writer+import Data.Function ( on )+import Data.List+import qualified Data.Map as Map+import Data.Maybe (catMaybes, fromMaybe, isJust, isNothing)+import Data.Tree (Tree(Node))+import qualified Data.Text as T+import Data.Text ( Text )++import Data.FullList hiding ( head, tail, (++) )+import qualified Data.FullList as FL++import NLP.GenI.FeatureStructure (Flist, AvPair(..), unifyFeat)+import NLP.GenI.General+ ( filterTree, repAllNode, histogram, geniBug, repNodeByNode,+ )+import NLP.GenI.GeniVal( unify, GeniVal(gConstraints), isConst, Subst, replace, finaliseVars )+import NLP.GenI.LexicalSelection.Types+import NLP.GenI.Lexicon ( LexEntry(..), Lexicon, )+import NLP.GenI.Semantics ( subsumeSem, unifySem, Sem )+import NLP.GenI.Tag ( TagElem(..), idname )+import NLP.GenI.TreeSchema ( Ttree(..), SchemaTree, SchemaNode, Macros+ , crushTreeGNode+ , setAnchor, setLexeme, tree+ , GNode(..), GType(..)+ )+import NLP.GenI.Warning++-- ----------------------------------------------------------------------+-- * Lexical selection algorithms+-- ----------------------------------------------------------------------++-- | See 'NLP.GenI.Configuration' if you want to use GenI with a custom+-- lexical selection function.+type LexicalSelector = Macros -> Lexicon -> Sem -> IO LexicalSelection++-- | The result of the lexical selection process+data LexicalSelection = LexicalSelection+ { -- | the main result: a set of elementary trees (ie. anchored trees)+ lsAnchored :: [TagElem]+ -- | if available, lexical entries that were used to produce anchored+ -- trees (useful for identifying anchoring failure)+ , lsLexEntries :: [LexEntry]+ -- | HINT: use 'Data.Monoid.mempty' to initialise to empty+ , lsWarnings :: GeniWarnings+ }++-- | Performs standard GenI lexical selection as described in+-- <http://projects.haskell.org/GenI/manual/lexical-selection.html>+--+-- This is just 'defaultLexicalSelection' lifted into IO+defaultLexicalSelector :: Macros -> Lexicon -> Sem -> IO LexicalSelection+defaultLexicalSelector g l t = return (defaultLexicalSelection g l t)++-- | Helper for 'defaultLexicalSelector'+-- (Standard GenI lexical selection is actually pure)+--+-- This is just 'defaultLexicalChoice' and 'defaultAnchoring'+defaultLexicalSelection :: Macros -> Lexicon -> Sem -> LexicalSelection+defaultLexicalSelection grammar lexicon tsem =+ defaultAnchoring grammar (defaultLexicalChoice lexicon tsem) tsem++-- | @missingLexEntries ts lexs@ returns any of the lexical candidates+-- @lexs@ that were apparently not anchored succesfully.+--+-- TODO: it does this by (wrongly) checking for each lexical item+-- to see if any of the anchored trees in @ts@ have identical+-- semantics to that lexical item. The better way to do this would+-- be to throw a subsumption check on top of items reported missing,+-- because it's possible for the trees to add semantics through+-- unification.+missingLexEntries :: [TagElem] -> [LexEntry] -> [LexEntry]+missingLexEntries cands = filter treeless+ where+ treeless l = isNothing $ find (\t -> tsemantics t == isemantics l) cands++-- ----------------------------------------------------------------------+-- * Selecting candidate lemmas+-- ----------------------------------------------------------------------++-- | Select and returns the set of entries from the lexicon whose semantics+-- subsumes the input semantics.+defaultLexicalChoice :: Lexicon -> Sem -> [LexEntry]+defaultLexicalChoice slex tsem = chooseCandI tsem slex++-- | 'chooseCandI' @sem l@ attempts to unify the semantics of @l@ with @sem@+-- If this succeeds, we use return the result(s); if it fails, we reject+-- @l@ as a lexical selection candidate.+chooseCandI :: Sem -> [LexEntry] -> [LexEntry]+chooseCandI tsem cand =+ let replaceLex i (sem,sub) =+ (replace sub i) { isemantics = sem }+ --+ helper :: LexEntry -> [LexEntry]+ helper l = if null sem then [l]+ else map (replaceLex l) psubsem+ where psubsem = sem `subsumeSem` tsem+ sem = isemantics l+ --+ in nub $ concatMap helper cand++-- | `mergeSynonyms' is a factorisation technique that uses+-- atomic disjunction to merge all synonyms into a single lexical+-- entry. Two lexical entries are considered synonyms if their+-- semantics match and they point to the same tree families.+-- +-- FIXME: 2006-10-11 - note that this is no longer being used,+-- because it breaks the case where two lexical entries differ+-- only by their use of path equations. Perhaps it's worthwhile+-- just to add a check that the path equations match exactly.+mergeSynonyms :: [LexEntry] -> [LexEntry]+mergeSynonyms lexEntry =+ let mergeFn l1 l2 = l1 { iword = (FL.++) (iword l1) (iword l2) }+ keyFn l = (ifamname l, isemantics l)+ synMap = foldr helper Map.empty lexEntry+ where helper x acc = Map.insertWith mergeFn (keyFn x) x acc+ in Map.elems synMap++-- --------------------------------------------------------------------+-- * Anchoring+-- --------------------------------------------------------------------++-- | The 'LexCombine' monad supports warnings during lexical selection+-- and also failure via Maybe+type LexCombine a = MaybeT (Writer [LexCombineError]) a++-- | Note an anchoring error+lexTell :: LexCombineError -> LexCombine ()+lexTell x = lift (tell [x])++-- | @defaultAnchoring schemata lex sem@ implements the later half of lexical+-- selection (tree anchoring and enrichement). It assumes that @lex@ consists+-- just of the lexical items that have been selected, and tries to combine them+-- with the tree schemata.+--+-- This function may be useful if you are implementing your own lexical selection+-- functions, and you want GenI to take over after you've given it a @[LexEntry]@+defaultAnchoring :: Macros -> [LexEntry] -> Sem -> LexicalSelection+defaultAnchoring grammar lexCands tsem =+ LexicalSelection { lsAnchored = cands+ , lsLexEntries = lexCands+ , lsWarnings = mconcat [ lexWarnings, coanchorWarnings, errs ]+ }+ where+ combinations = map (combineList tsem grammar) lexCands+ cands = concatMap snd combinations+ errs = mkGeniWarnings . concat $ zipWith mkWarnings lexCands (map fst combinations)+ mkWarnings l = map (LexWarning [l] . LexCombineOneSchemaFailed)+ coanchorWarnings = mkGeniWarnings $ do -- list monad+ l <- lexCands+ let xs = filter (\p -> pfamily p == ifamname l) grammar+ (c,n) <- Map.toList . histogram $ concatMap (missingCoanchors l) xs+ return (LexWarning [l] (MissingCoanchors c n))+ lexWarnings = mkGeniWarnings $ case missingLexEntries cands lexCands of+ [] -> []+ xs -> [LexWarning xs LexCombineAllSchemataFailed]+++-- ----------------------------------------------------------------------+-- ** Combination+-- ----------------------------------------------------------------------++-- | Given a lexical item, looks up the tree families for that item, and+-- anchor the item to the trees.+combineList :: Sem -> Macros -> LexEntry+ -> ([LexCombineError],[TagElem]) -- ^ any warnings, plus the results+combineList tsem gram lexitem =+ case [ t | t <- gram, pfamily t == tn ] of+ [] -> ([FamilyNotFoundError tn],[])+ macs -> squish . swap . unzip $ map (\m -> runWriter . runMaybeT $ combineOne tsem lexitem m) macs+ where+ tn = ifamname lexitem+ swap (x,y) = (y,x)+ squish = (compressLexCombineErrors . concat) *** (concat . catMaybes)++-- | Combine a single tree with its lexical item to form a bonafide TagElem.+-- This process can fail, however, because of filtering or enrichement+combineOne :: Sem -> LexEntry -> SchemaTree -> LexCombine [TagElem]+combineOne tsem lexRaw eRaw = -- Maybe monad+ -- trace ("\n" ++ (show wt)) $+ do let l1 = finaliseVars "-l" lexRaw+ e1 = finaliseVars "-t" eRaw+ (l,e) <- unifyParamsWithWarning (l1,e1)+ >>= unifyInterfaceUsing iinterface+ >>= unifyInterfaceUsing ifilters -- filtering+ >>= enrichWithWarning -- enrichment+ tree2 <- case crushTreeGNode (tree e) of+ Nothing -> do lexTell (SchemaError [pidname e]+ (StringError "Could not flatten disjunction"))+ fail ""+ Just x -> return x+ let name = T.intercalate ":" $ filter (not . T.null)+ [ FL.head (iword l) , pfamily e , pidname e ]+ template = TE+ { idname = name+ , ttreename = pfamily e+ , tidnum = -1 -- provisional id+ , ttype = ptype e+ , ttree = setOrigin name . setLemAnchors . setAnchor (iword l) $ tree2+ , tsemantics = []+ , tsempols = isempols l+ , tpolarities = Map.empty+ , tinterface = pinterface e+ , ttrace = ptrace e+ }+ semUnifications <- case unifySem (isemantics l) (fromMaybe [] $ psemantics e) of+ [] -> do lexTell (SchemaError [pidname e] (StringError "could not unify lemma and schema semantics"))+ fail ""+ xs -> return xs+ return $ concatMap (finaliseSemantics template) semUnifications+ where+ croak t msg = do+ lexTell (SchemaError [pidname t] (StringError msg))+ fail ""+ finaliseSemantics template (sem,sub) =+ do (sem2,sub2) <- sem `subsumeSem` replace sub tsem+ return $ replace sub2 $ template { tsemantics = sem2 }+ unifyParamsWithWarning (l,t) =+ -- trace ("unify params " ++ wt) $+ let lp = iparams l+ tp = params t+ in if length lp /= length tp+ then croak t "Parameter length mismatch"+ else case unify lp tp of+ Nothing -> croak t "Parameter unification error"+ Just (ps2, subst) -> return (replace subst l, t2)+ where t2 = (replace subst t) { params = ps2 }+ unifyInterfaceUsing ifn (l,e) =+ -- trace ("unify interface" ++ wt) $+ case unifyFeat (ifn l) (pinterface e) of+ Nothing -> croak e "Interface unification error"+ Just (int2, fsubst) -> return (replace fsubst l, e2)+ where e2 = (replace fsubst e) { pinterface = int2 }+ --+ enrichWithWarning (l,e) =+ -- trace ("enrich" ++ wt) $+ do e2 <- enrich l e+ return (l,e2)++-- ----------------------------------------------------------------------+-- ** Enrichment+-- ----------------------------------------------------------------------++-- | See <http://projects.haskell.org/manual/lexical-selection>+-- on enrichement+enrich :: LexEntry -> SchemaTree -> LexCombine SchemaTree+enrich l t =+ do -- separate into interface/anchor/named+ (intE, namedE) <- lift $ lexEquations l+ -- enrich the interface and everything else+ t2 <- foldM enrichInterface t intE+ -- enrich everything else+ foldM enrichBy t2 namedE+ where+ enrichInterface tx en =+ case unifyFeat [en] (pinterface tx) of+ Nothing -> lexTell (ifaceEnrichErr en) >> fail ""+ Just (i2, isubs) -> return $ (replace isubs tx) { pinterface = i2 }+ ifaceEnrichErr (AvPair loc _) =+ SchemaError [pidname t] (EnrichError (PeqInterface loc))++-- *** 'enrich' helpers++-- | Helper for 'enrich' (enrich by single path equation)+enrichBy :: SchemaTree+ -> PathEqPair+ -> LexCombine SchemaTree+enrichBy t eq@(eqLhs, _) =+ case maybeEnrichBy t eq of+ Nothing -> lexTell enrichErr >> return t+ Just (t2,_) -> return t2+ where+ enrichErr = SchemaError [pidname t] (EnrichError (PeqJust eqLhs))++-- | Helper for 'enrichBy'+maybeEnrichBy :: SchemaTree+ -> PathEqPair+ -> Maybe (SchemaTree, Subst)+maybeEnrichBy t (eqLhs, eqVal) = do+ node <- seekCoanchor eqLhs t+ case eqLhs of+ PeqFeat _ eqTop eqAtt -> do+ let (get, set) = case eqTop of+ Top -> (gup, \n x -> n { gup = x })+ Bottom -> (gdown, \n x -> n { gdown = x})+ (fs, sub) <- enrichFeat (AvPair eqAtt eqVal) (get node)+ let t2 = fixNode (set node fs) (replace sub t)+ return (t2, sub)+ PeqLex _ -> do+ vs <- gConstraints eqVal+ let node2 = node { glexeme = FL.fromFL vs }+ t2 = fixNode node2 t+ return (t2, Map.empty)+ where+ fixNode n mt = mt { tree = repNodeByNode (matchNodeName eqLhs) n (tree mt) }++-- | @enrichFeat av fs@ attempts to unify @av@ with @fs@+--+-- Note here that @fs@ is an @Flist [GeniVal]@ rather than the usual+-- @Flist GeniVal@ you may expect. This is because it comes from+-- 'SchemaTree' which allows non-atomic disjunctions of @GeniVal@+-- which have to be flatten down to at most atomic disjunctions once+-- lexical selection is complete.+enrichFeat :: AvPair GeniVal -> Flist [GeniVal] -> Maybe (Flist [GeniVal], Subst)+enrichFeat (AvPair a v) fs =+ case span (\x -> avAtt x < a) fs of+ (before,here:after) | avMatch here ->+ do let (AvPair _ fv) = here+ (v2,sub) <- unify fv (replicate (length fv) v)+ let av2 = AvPair a v2+ fs2 = replace sub before ++ (av2 : replace sub after)+ return (fs2, sub)+ (before,after) ->+ let av2 = AvPair a [v]+ fs2 = before ++ (av2 : after) in Just (fs2, Map.empty)+ where+ avMatch (AvPair fa _) = fa == a++-- | @missingCoanchors l t@ returns the list of coanchor node names from @l@+-- that were not found in @t@+missingCoanchors :: LexEntry -> SchemaTree -> [Text]+missingCoanchors lexEntry t =+ [ name eqLhs | eqLhs <- nubBy ((==) `on` name) equations, missing eqLhs ]+ where+ equations = map fst . snd . fst . runWriter $ lexEquations lexEntry+ name (PeqFeat n _ _) = n+ name (PeqLex n) = n+ missing eqLhs = isNothing (seekCoanchor eqLhs t)++-- | Split a lex entry's path equations into interface enrichement equations+-- or (co-)anchor modifiers+lexEquations :: LexEntry -> Writer [LexCombineError] ([AvPair GeniVal],[PathEqPair])+lexEquations =+ fmap myPartition . mapM parseAv . iequations+ where+ myPartition xs = ( [ AvPair a v | (PeqInterface a, v) <- xs ]+ , [ (n,v) | (PeqJust n, v) <- xs ] )+ parseAv (AvPair a v) = fmap (\a2 -> (a2,v)) (parsePathEq a)++-- | @seekCoanchor lhs t@ returns @Just node@ if @t@ contains exactly one+-- node that can be identified by @lhs@, @Nothing@ if it contains none.+--+-- It crashes if there is more than one such node, because this should+-- have been caught earlier by GenI.+seekCoanchor :: NodePathEqLhs -> SchemaTree -> Maybe SchemaNode+seekCoanchor eqLhs t =+ case filterTree (matchNodeName eqLhs) (tree t) of+ [a] -> Just a+ [] -> Nothing+ _ -> geniBug . T.unpack . T.intercalate "\n" $+ [ "NLP.GenI.LexicalSelection.seekCoanchor:"+ , "Did not expect to see a tree with multiple matches in enrichBy."+ , "Tree: " `T.append` pidname t+ , "Family: " `T.append` pfamily t+ , "Matching on: " `T.append` showPathEqLhs (PeqJust eqLhs)+ ]++-- | @matchNodeName lhs n@ is @True@ if the @lhs@ refers to the node @n@+matchNodeName :: NodePathEqLhs -> SchemaNode -> Bool+matchNodeName (PeqFeat n _ _) = matchNodeNameHelper n+matchNodeName (PeqLex n) = matchNodeNameHelper n++-- | @matchNodeNameHelper@ recognises “anchor“ by convention; otherwise,+-- it does a name match+matchNodeNameHelper :: Text -> SchemaNode -> Bool+matchNodeNameHelper "anchor" = ganchor+matchNodeNameHelper n = (== n) . gnname++-- ----------------------------------------------------------------------+-- ** Lemanchor mechanism+-- ----------------------------------------------------------------------++-- | The lemanchor mechanism is described in+-- <http://projects.haskell.org/manual/lexical-selection>+setLemAnchors :: Tree (GNode GeniVal) -> Tree (GNode GeniVal)+setLemAnchors t =+ repAllNode fn filt t+ where+ filt (Node a []) = gtype a == Subs && (isJust. lemAnchor) a+ filt _ = False+ fn (Node x k) = setLexeme (lemAnchorMaybeFake x) $+ Node (x { gtype = Other, gaconstr = False }) k+ --+ lemAnchorMaybeFake :: GNode GeniVal -> [Text]+ lemAnchorMaybeFake n =+ fromMaybe ["ERR_UNSET_LEMMANCHOR"] (lemAnchor n)+ lemAnchor :: GNode GeniVal -> Maybe [Text]+ lemAnchor n =+ case [ v | AvPair a v <- gup n, a == _lemanchor ] of+ [l] | isConst l -> fromFL <$> gConstraints l+ _ -> Nothing++-- | The name of the lemanchor attribute (by convention; see source)+_lemanchor :: Text+_lemanchor = "lemanchor"++-- | @setOrigin n t@ marks the nodes in @t@ as having come from+-- a tree named @n@+setOrigin :: Text -> Tree (GNode v) -> Tree (GNode v)+setOrigin t = fmap (\g -> g { gorigin = t })
+ src/NLP/GenI/LexicalSelection/Types.hs view
@@ -0,0 +1,149 @@+-- GenI surface realiser+-- Copyright (C) 2012 Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE OverloadedStrings #-}+module NLP.GenI.LexicalSelection.Types where++import Control.Monad.Writer+import Data.List+import Data.Poset+import Data.Text ( Text )+import qualified Data.Map as Map+import qualified Data.Text as T++import NLP.GenI.GeniVal+import NLP.GenI.Pretty++-- | Left hand side of a path equation+data PathEqLhs = PeqInterface Text+ | PeqJust NodePathEqLhs+ | PeqUnknown Text+ deriving (Eq, Ord)++-- ----------------------------------------------------------------------+-- * Path equations+-- ----------------------------------------------------------------------++-- | Path equations can either hit a feature or a node's lexeme attribute+data NodePathEqLhs = PeqFeat Text TopBottom Text+ | PeqLex Text+ deriving (Eq, Ord)++data TopBottom = Top | Bottom+ deriving (Eq, Ord)++type PathEqPair = (NodePathEqLhs, GeniVal)++-- | Parse a path equation using the GenI conventions+-- This always succeeds, but can return @Just warning@+-- if anything anomalous comes up+-- FIXME : make more efficient+parsePathEq :: Text -> Writer [LexCombineError] PathEqLhs+parsePathEq e =+ case T.splitOn "." e of+ (n:"top":r) -> return (node n Top r)+ (n:"bot":r) -> return (node n Bottom r)+ [n,"lex"] -> return (PeqJust (PeqLex n))+ ("top":r) -> return (node "anchor" Top r)+ ("bot":r) -> return (node "anchor" Bottom r)+ ("anchor":r) -> return (node "anchor" Bottom r)+ ("interface":r) -> return (PeqInterface (rejoin r))+ ("anc":r) -> parsePathEq $ rejoin ("anchor":r)+ (n:r@(_:_)) -> tell [BoringError (tMsg n)] >> return (node n Top r)+ _ -> tell [BoringError iMsg ] >> return (PeqUnknown e)+ where+ node n tb r = PeqJust $ PeqFeat n tb (rejoin r)+ rejoin = T.intercalate "."+ tMsg n = T.unwords+ [ "Interpreting path equation"+ , e+ , "as applying to top of"+ , n `T.snoc` '.'+ ]+ iMsg = "Could not interpret path equation" <+> e++showPathEqLhs :: PathEqLhs -> Text+showPathEqLhs p =+ case p of+ PeqJust (PeqFeat n tb att) -> squish [ n, fromTb tb, att ]+ PeqJust (PeqLex n) -> squish [ n, "lex" ]+ PeqInterface att -> squish [ "interface", att ]+ PeqUnknown e -> e+ where+ fromTb Top = "top"+ fromTb Bottom = "bot"+ squish = T.intercalate "."++-- ----------------------------------------------------------------------+-- * Warnings+-- ----------------------------------------------------------------------++data LexCombineError =+ BoringError Text+ | FamilyNotFoundError Text+ | SchemaError [Text] LexCombineError2+ deriving Eq++data LexCombineError2 = EnrichError PathEqLhs+ | StringError Text+ deriving (Eq, Ord)++instance Poset LexCombineError where+ leq (BoringError _) _ = True+ leq (SchemaError _ e1) (SchemaError _ e2) = leq e1 e2+ leq (FamilyNotFoundError x1) (FamilyNotFoundError x2) = leq x1 x2+ leq (FamilyNotFoundError _) (SchemaError _ _) = True+ leq _ _ = False++instance Poset LexCombineError2 where+ leq (EnrichError e1) (EnrichError e2) = leq e1 e2+ leq (EnrichError _ ) (StringError _ ) = True+ leq (StringError s1) (StringError s2) = leq s1 s2+ leq _ _ = False++instance Poset PathEqLhs where+ leq l1 l2 = leq (showPathEqLhs l1) (showPathEqLhs l2)++instance Poset Text where+ leq l1 l2 = leq (T.unpack l1) (T.unpack l2)++instance Pretty LexCombineError where+ pretty e =+ body <+> suffix+ where+ (body, suffix) = showLexCombineError e++showLexCombineError :: LexCombineError -> (Text, Text)+showLexCombineError (SchemaError xs x) = (pretty x, prettyCount (const "") "trees" ((), length xs))+showLexCombineError (BoringError s) = (s, "")+showLexCombineError (FamilyNotFoundError f) = ("Family" <+> f <+> "not found in tree schema file", "")++instance Pretty LexCombineError2 where+ pretty (EnrichError p) =+ "Some trees discarded due to enrichment error on" <+> showPathEqLhs p+ pretty (StringError s) = s++compressLexCombineErrors :: [LexCombineError] -> [LexCombineError]+compressLexCombineErrors errs = schema2 ++ normal+ where+ isSchema (SchemaError _ _) = True+ isSchema _ = False+ (schema, normal) = partition isSchema errs+ schema2 = map (uncurry (flip SchemaError))+ . Map.toList+ $ Map.fromListWith (++) [ (l,ts) | SchemaError ts l <- schema ]
+ src/NLP/GenI/Lexicon.hs view
@@ -0,0 +1,27 @@+-- GenI surface realiser+-- Copyright (C) 2005-2009 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++module NLP.GenI.Lexicon (+ Lexicon,+ -- anything but the constructor+ LexEntry, mkLexEntry, mkFullLexEntry,+ iword , ifamname, iparams, iinterface , ifilters, iequations, isemantics, isempols,+ -- * Converting between lexical/normal semantics+ PolValue, fromLexSem, fromLexLiteral,+) where++import NLP.GenI.Lexicon.Internal
+ src/NLP/GenI/Lexicon/Internal.hs view
@@ -0,0 +1,203 @@+-- GenI surface realiser+-- Copyright (C) 2005-2009 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}+module NLP.GenI.Lexicon.Internal where++-- import Debug.Trace -- for test stuff+import Data.Binary+import Data.FullList+import Data.Function+import Data.List ( sortBy )+import Data.Generics (Data)+import Data.Text ( Text )+import Data.Typeable (Typeable)+import qualified Data.Text as T++import NLP.GenI.FeatureStructure+import NLP.GenI.GeniShow+import NLP.GenI.GeniVal+import NLP.GenI.Pretty+import NLP.GenI.Semantics+import NLP.GenI.Polarity.Types (SemPols)++import Control.DeepSeq++--instance Show (IO()) where+-- show _ = ""++type Lexicon = [LexEntry]+data LexEntry = LexEntry+ { -- normally just a singleton, useful for merging synonyms+ iword :: FullList Text+ , ifamname :: Text+ , iparams :: [GeniVal]+ , iinterface :: Flist GeniVal+ , ifilters :: Flist GeniVal+ , iequations :: Flist GeniVal+ , isemantics :: Sem+ , isempols :: [SemPols] }+ deriving (Eq, Data, Typeable)++-- | See also 'mkFullLexEntry'+-- This version comes with some sensible defaults.+mkLexEntry :: FullList Text -- ^ word+ -> Text -- ^ family name+ -> [GeniVal] -- ^ parameters list (deprecated)+ -> Flist GeniVal -- ^ interface (use instead of params)+ -> Flist GeniVal -- ^ filters+ -> Flist GeniVal -- ^ equations+ -> Sem -- ^ semantics+ -> LexEntry+mkLexEntry word famname params interface filters equations sem =+ mkFullLexEntry word famname params interface filters equations+ sem (map noSemPols sem)+ where+ noSemPols l = replicate (length (lArgs l)) 0++-- | Variant of 'mkLexEntry' but with more control+mkFullLexEntry :: FullList Text -- ^ word+ -> Text -- ^ family name+ -> [GeniVal] -- ^ parameters list (deprecated)+ -> Flist GeniVal -- ^ interface (use instead of params)+ -> Flist GeniVal -- ^ filters+ -> Flist GeniVal -- ^ equations+ -> Sem -- ^ semantics+ -> [SemPols] -- ^ semantic polarities+ -> LexEntry+mkFullLexEntry word famname params interface filters equations sem sempols =+ LexEntry+ (sortNub word)+ famname+ params+ (sortFlist interface)+ (sortFlist filters)+ (sortFlist equations)+ sem2+ sempols2+ where+ (sem2, sempols2) = unzip $ sortBy (compareOnLiteral `on` fst) (zip sem sempols)++instance DescendGeniVal LexEntry where+ descendGeniVal s i =+ i { iinterface = descendGeniVal s (iinterface i)+ , iequations = descendGeniVal s (iequations i)+ , isemantics = descendGeniVal s (isemantics i)+ , iparams = descendGeniVal s (iparams i) }++instance Collectable LexEntry where+ collect l = (collect $ iinterface l) . (collect $ iparams l) .+ (collect $ ifilters l) . (collect $ iequations l) .+ (collect $ isemantics l)++-- ----------------------------------------------------------------------+-- lexicon semantics+-- ----------------------------------------------------------------------++-- | An annotated GeniVal. This is for a rather old, obscure+-- variant on the polarity filtering optimisation. To account+-- for zero literal semantics, we annotate each value in the+-- semantics with a positive/negative marker. These markers+-- are then counted up to determine with we need to insert+-- more literals into the semantics or not. See the manual+-- on polarity filtering for more details+type PolValue = (GeniVal, Int)++fromLexSem :: [Literal PolValue] -> (Sem, [SemPols])+fromLexSem = unzip . map fromLexLiteral++-- | Note that by convention we ignore the polarity associated+-- with the predicate itself+fromLexLiteral :: Literal PolValue -> (Literal GeniVal, SemPols)+fromLexLiteral (Literal h pr vs) =+ (lit, pols)+ where+ lit = Literal (fst h) (fst pr) (map fst vs)+ pols = snd h : map snd vs++-- ----------------------------------------------------------------------+-- converting to text+-- ----------------------------------------------------------------------++-- TODO: does not support semantic polarities yet+instance GeniShow LexEntry where+ geniShowText l = T.intercalate "\n"+ [ T.unwords+ [ geniShowText . mkGConst $ iword l+ , ifamname l+ , paramT+ ]+ , geniKeyword "equations" $ geniShowText (iequations l)+ , geniKeyword "filters" $ geniShowText (ifilters l)+ , geniKeyword "semantics" $ geniShowText (isemantics l)+ ]+ where + paramT = parens . T.unwords . concat $+ [ map geniShowText (iparams l)+ , ["!"]+ , map geniShowText (iinterface l)+ ]++instance GeniShow [LexEntry] where+ geniShowText = T.intercalate "\n\n" . map geniShowText++instance Pretty LexEntry where+ pretty = geniShowText++-- ----------------------------------------------------------------------+--+-- ----------------------------------------------------------------------++{-!+deriving instance Binary LexEntry+deriving instance NFData LexEntry+!-}++-- GENERATED START++ +instance Binary LexEntry where+ put (LexEntry x1 x2 x3 x4 x5 x6 x7 x8)+ = do put x1+ put x2+ put x3+ put x4+ put x5+ put x6+ put x7+ put x8+ get+ = do x1 <- get+ x2 <- get+ x3 <- get+ x4 <- get+ x5 <- get+ x6 <- get+ x7 <- get+ x8 <- get+ return (LexEntry x1 x2 x3 x4 x5 x6 x7 x8)++ +instance NFData LexEntry where+ rnf (LexEntry x1 x2 x3 x4 x5 x6 x7 x8)+ = rnf x1 `seq`+ rnf x2 `seq`+ rnf x3 `seq`+ rnf x4 `seq` rnf x5 `seq` rnf x6 `seq` rnf x7 `seq` rnf x8 `seq` ()+-- GENERATED STOP
+ src/NLP/GenI/Main.hs view
@@ -0,0 +1,58 @@+-- GenI surface realiser+-- Copyright (C) 2005 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++{-# LANGUAGE CPP #-}+module NLP.GenI.Main where++import Control.Applicative ((<$>))+import Data.IORef(newIORef)+import Data.Typeable( Typeable )+import Data.Version ( showVersion )+import System.Environment(getArgs, getProgName)++import Paths_GenI ( version )++import NLP.GenI.Console(consoleGeni)+import NLP.GenI.Configuration (treatArgs, optionsForStandardGenI, processInstructions,+ usage, optionsSections, Params,+ hasFlagP, DisableGuiFlg(..),+ HelpFlg(..), VersionFlg(..),+ readGlobalConfig, setLoggers+ )+import NLP.GenI.Configuration(setFlagP)+import NLP.GenI ( ProgState(..), emptyProgState )++main :: IO ()+main = do+ args <- getArgs+ confArgs <- forceGuiFlag <$> (processInstructions =<< treatArgs optionsForStandardGenI args)+ mainWithState (emptyProgState confArgs)++mainWithState :: ProgState -> IO ()+mainWithState pst = do+ pname <- getProgName+ maybe (return ()) setLoggers =<< readGlobalConfig+ pstRef <- newIORef pst+ let has :: (Typeable f, Typeable x) => (x -> f) -> Bool+ has = flip hasFlagP (pa pst)+ case () of+ _ | has HelpFlg -> putStrLn (usage optionsSections pname)+ | has VersionFlg -> putStrLn (pname ++ " " ++ showVersion version)+ | otherwise -> consoleGeni pstRef++forceGuiFlag :: Params -> Params+forceGuiFlag = setFlagP DisableGuiFlg ()
+ src/NLP/GenI/Morphology.hs view
@@ -0,0 +1,218 @@+-- GenI surface realiser+-- Copyright (C) 2005 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++{-|+This module handles mostly everything to do with morphology in Geni.+There are two basic tasks: morphological input and output.+GenI farms out morphology to whatever third party program you+specify on the command line. Note that a simple and stupid+``sillymorph'' realiser is provided either in the GenI repository+or on hackage.+-}++{-# LANGUAGE DeriveDataTypeable #-}+module NLP.GenI.Morphology+ (+ module NLP.GenI.Morphology.Types+ -- * Morphological predicates+ , readMorph, stripMorphSem, attachMorph, setMorphAnchor+ -- * Morphological realisation+ , inflectSentencesUsingCmd, sansMorph+ ) where++import Control.Concurrent (forkIO)+import Control.Exception (catch, bracket, evaluate, IOException)+import Data.Maybe (isNothing)+import Data.Text ( Text )+import Data.Tree+import Data.Typeable+import System.Exit+import System.IO+import System.Process+import Prelude hiding (catch)+import qualified Data.Map as Map+import qualified Data.Text as T++import System.Log.Logger+import Text.JSON+import Text.JSON.Pretty++import NLP.GenI.FeatureStructure+import NLP.GenI.GeniVal ( mkGAnon, GeniVal, replace )+import NLP.GenI.General+import NLP.GenI.Morphology.Types+import NLP.GenI.Pretty+import NLP.GenI.Semantics ( Literal(..), Sem )+import NLP.GenI.Tag+import NLP.GenI.TreeSchema ( GNode(..), GType(..) )++-- ----------------------------------------------------------------------+-- Morphological input+-- ----------------------------------------------------------------------++-- | Converts information from a morphological information file into GenI's+-- internal format.+readMorph :: [(Text,[AvPair GeniVal])] -> MorphInputFn+readMorph minfo lit =+ Map.lookup key fm+ where+ fm = Map.fromList minfo+ key = pretty (lPredicate lit)++-- | Filters away from an input semantics any literals whose realisation is+-- strictly morphological. The first argument tells us helps identify the+-- morphological literals -- it associates literals with morphological stuff;+-- if it returns 'Nothing', then it is non-morphological+stripMorphSem :: MorphInputFn -> Sem -> Sem+stripMorphSem morphfn tsem = + [ l | l <- tsem, (isNothing.morphfn) l ]++-- | 'attachMorph' @morphfn sem cands@ does the bulk of the morphological+-- input processing. We use @morphfn@ to determine which literals in+-- @sem@ contain morphological information and what information they contain.+-- Then we attach this morphological information to the relevant trees in+-- @cand@. A tree is considered relevant w.r.t to a morphological+-- literal if its semantics contains at least one literal whose first index+-- is the same as the first index of the morphological literal.+attachMorph :: MorphInputFn -> Sem -> [TagElem] -> [TagElem]+attachMorph morphfn sem cands = + let -- relevance of a tree wrt to an index+ relTree i = not.null.relfilt.tsemantics+ where relfilt = filter (relLit i) + relLit i l = case lArgs l of+ [] -> False+ (x:_) -> x == i+ -- perform the attachment for a tree if it is relevant+ attachHelper :: GeniVal -> Flist GeniVal -> TagElem -> TagElem+ attachHelper i mfs t = + if relTree i t then attachMorphHelper mfs t else t + -- perform all attachments for a literal+ attach :: Literal GeniVal -> [TagElem] -> [TagElem]+ attach l cs = + case morphfn l of + Nothing -> cs+ Just mfs -> map (attachHelper i mfs) cs+ where i = case lArgs l of+ [] -> mkGAnon+ (x:_) -> x+ in foldr attach cands sem ++-- | Actually unify the morphological features into the anchor node+--+-- FIXME: we'll need to make sure this still works as promised +-- when we implement co-anchors.+attachMorphHelper :: Flist GeniVal -> TagElem -> TagElem+attachMorphHelper mfs te = + let -- unification with anchor+ tt = ttree te + anchor = head $ filterTree fn tt+ where fn a = (ganchor a && gtype a == Lex)+ in case unifyFeat mfs (gup anchor) of+ Nothing -> error ("Morphological unification failure on " ++ T.unpack (idname te))+ Just (unf,subst) ->+ let -- perform replacements+ te2 = replace subst te + tt2 = ttree te2+ -- replace the anchor with the unification results+ newgdown = replace subst (gdown anchor) + newa = anchor { gup = unf, gdown = newgdown }+ in te2 { ttree = setMorphAnchor newa tt2 }++setMorphAnchor :: GNode GeniVal -> Tree (GNode GeniVal) -> Tree (GNode GeniVal)+setMorphAnchor n t =+ let filt (Node a _) = (gtype a == Lex && ganchor a)+ fn (Node _ l) = Node n l+ in (head.fst) $ listRepNode fn filt [t]++-- ----------------------------------------------------------------------+-- Morphological realisation+-- ----------------------------------------------------------------------++-- | Extracts the lemmas from a list of uninflected sentences. This is used+-- when the morphological generator is unavailable, doesn't work, etc.+sansMorph :: LemmaPlusSentence -> MorphOutput+sansMorph =+ MorphOutput [] . singleton . T.unwords . map lem+ where+ lem (LemmaPlus l _) = l++-- | Converts a list of uninflected sentences into inflected ones by calling+--- the third party software.+-- FIXME: this doesn't actually support lists-of-results per input+-- will need to work it out+-- HUH? What makes me say that?+inflectSentencesUsingCmd :: String -> [LemmaPlusSentence] -> IO [(LemmaPlusSentence,MorphOutput)]+inflectSentencesUsingCmd morphcmd sentences =+ doit `catch` \e -> let _ = e :: IOException in (fallback (show e))+ where+ hCloseSloppy h = hClose h `catch` \err -> let _ = err :: IOException in warningM logname (show err)+ doit = bracket+ (do debugM logname $ "Starting morph generator: " ++ morphcmd + runInteractiveCommand morphcmd)+ (\(inh,outh,errh,_) -> do+ debugM logname $ "Closing output handles from morph generator"+ mapM hCloseSloppy [inh, outh, errh])+ $ \(toP,fromP,errP,pid) -> do+ debugM logname $ "Sending " ++ show (length sentences) ++ " sentences to morph generator"+ hPutStrLn toP . render . pp_value . showJSON $ sentences++ debugM logname $ "Closing input handle to morph generator"+ hClose toP+ -- see http://www.haskell.org/pipermail/haskell-cafe/2008-May/042994.html+ -- fork off a thread to pull on the stderr+ -- so if the process writes to stderr we do not block.+ -- NB. do the hGetContents synchronously, otherwise the outer+ -- bracket can exit before this thread has run, and hGetContents+ -- will fail.+ err <- hGetContents errP+ _ <- forkIO (evaluate (length err) >> warningM logname err)++ -- wait for all the output+ output <- hGetContents fromP+ _ <- evaluate (length output)++ -- wait for the program to terminate+ exitcode <- waitForProcess pid+ debugM logname $ "Morph command exited"+ -- on failure, throw the exit code as an exception+ if exitcode == ExitSuccess+ then case resultToEither (decode output) of+ Left jerr -> fallback $ "Could not parse morphological generator output: " ++ jerr+ Right res -> do let lenResults = length res+ lenSentences = length sentences+ if lenResults == lenSentences+ then return $ zip sentences res+ else fallback $ "Morphological generator returned "+ ++ show lenResults ++ " results for "+ ++ show lenSentences ++ " inputs"+ `catch` \e -> let _ = e :: IOException+ in fallback ("Error calling morphological generator:\n" ++ show e)+ else fallback "Morph generator failed"+ fallback err = do+ errorM logname err+ return $ map (\x -> (x, sansMorph x)) sentences++-- ----------------------------------------------------------------------+-- odds and ends+-- ----------------------------------------------------------------------++singleton :: a -> [a]+singleton x = [x]++data MNAME = MNAME deriving Typeable+logname :: String+logname = mkLogname MNAME
− src/NLP/GenI/Morphology.lhs
@@ -1,233 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.--\chapter{Morphology}-\label{cha:Morphology}--This module handles mostly everything to do with morphology in Geni.-There are two basic tasks: morphological input and output.-GenI farms out morphology to whatever third party program you-specify on the command line. Note that a simple and stupid-``sillymorph'' realiser is provided either in the GenI repository-or on hackage.--\begin{code}-module NLP.GenI.Morphology- (- MorphFn- -- re-export- , LemmaPlus(..), LemmaPlusSentence- -- * Morphological predicates- , readMorph, stripMorphSem, attachMorph, setMorphAnchor- -- * Morphological realisation- , inflectSentencesUsingCmd, sansMorph- ) where-\end{code}--\ignore{-\begin{code}-import Data.Maybe (isNothing)-import Data.Tree-import qualified Data.Map as Map-import System.IO-import System.Process-import Text.JSON-import Text.JSON.Pretty--import NLP.GenI.Btypes-import NLP.GenI.General-import NLP.GenI.Tags-import NLP.GenI.Builder-\end{code}-}--\begin{code}-type MorphFn = Pred -> Maybe Flist-\end{code}--\section{Morphological input}--Morphological input means attaching morphological features on trees. The-user specifies morphological input through the input semantics. Our job-is to identify morphological predicates like \semexpr{plural(x)} and -apply features like \fs{\it num:pl} on the relevant trees.--\begin{code}--- | Converts information from a morphological information file into GenI's--- internal format.-readMorph :: [(String,[AvPair])] -> MorphFn-readMorph minfo pred_ = Map.lookup key fm- where fm = Map.fromList minfo- key = show $ snd3 pred_---- | Filters away from an input semantics any literals whose realisation is--- strictly morphological. The first argument tells us helps identify the--- morphological literals -- it associates literals with morphological stuff;--- if it returns 'Nothing', then it is non-morphological-stripMorphSem :: MorphFn -> Sem -> Sem-stripMorphSem morphfn tsem = - [ l | l <- tsem, (isNothing.morphfn) l ]---- | 'attachMorph' @morphfn sem cands@ does the bulk of the morphological--- input processing. We use @morphfn@ to determine which literals in--- @sem@ contain morphological information and what information they contain.--- Then we attach this morphological information to the relevant trees in--- @cand@. A tree is considered relevant w.r.t to a morphological--- literal if its semantics contains at least one literal whose first index--- is the same as the first index of the morphological literal.-attachMorph :: MorphFn -> Sem -> [TagElem] -> [TagElem]-attachMorph morphfn sem cands = - let -- relevance of a tree wrt to an index- relTree i = not.null.relfilt.tsemantics- where relfilt = filter (relLit i) - relLit i l = if null args then False else (head args == i)- where args = thd3 l- -- perform the attachment for a tree if it is relevant- attachHelper :: GeniVal -> Flist -> TagElem -> TagElem - attachHelper i mfs t = - if relTree i t then attachMorphHelper mfs t else t - -- perform all attachments for a literal- attach :: Pred -> [TagElem] -> [TagElem]- attach l cs = - case morphfn l of - Nothing -> cs- Just mfs -> map (attachHelper i mfs) cs- where i = if null args then GAnon else head args- args = thd3 l - in foldr attach cands sem ---- | Actually unify the morphological features into the anchor node------ FIXME: we'll need to make sure this still works as promised --- when we implement co-anchors.-attachMorphHelper :: Flist -> TagElem -> TagElem-attachMorphHelper mfs te = - let -- unification with anchor- tt = ttree te - anchor = head $ filterTree fn tt- where fn a = (ganchor a && gtype a == Lex)- in case unifyFeat mfs (gup anchor) of- Nothing -> error ("Morphological unification failure on " ++ idname te)- Just (unf,subst) ->- let -- perform replacements- te2 = replace subst te - tt2 = ttree te2- -- replace the anchor with the unification results- newgdown = replace subst (gdown anchor) - newa = anchor { gup = unf, gdown = newgdown }- in te2 { ttree = setMorphAnchor newa tt2 }--setMorphAnchor :: GNode -> Tree GNode -> Tree GNode-setMorphAnchor n t =- let filt (Node a _) = (gtype a == Lex && ganchor a)- fn (Node _ l) = Node n l- in (head.fst) $ listRepNode fn filt [t]-\end{code}--\section{Morphological realisation}--\jargon{Morphological realisation} refers to the actual process-of converting lemmas and morphological information into inflected forms.-We do this by calling some third party software specified by the user.--The morphological software must accept a JSON list of \jargon{lemma sentences}-where each lemma sentence is itself a list of objects containing a lemma and-a feature structure.--\begin{verbatim}-[- [{"lemma": "le", "lemma-features": "[num:sg gen:f]"},- {"lemma": "fille", "lemma-features": "[num:sg]"},- {"lemma": "detester", "lemma-features": "[num:sg tense:past]"},- {"lemma": "le", "lemma-features": "[num:pl gen:m]"},- {"lemma": "garcon", "lemma-features": "[num:pl]"}- ],-- [{"lemma": "ce", "lemma-features": "[]"},- {"lemma": "etre", "lemma-features": "[]"},- {"lemma": "le", "lemma-features": "[]"},- {"lemma": "garcon", "lemma-features": "[]"},- {"lemma": "que", "lemma-features": "[]"},- {"lemma": "le", "lemma-features": "[num:sg gen:f]"},- {"lemma": "fille", "lemma-features": "[num:sg]"},- {"lemma": "detester", "lemma-features": "[num:sg tense:past]"}- ]-]-\end{verbatim}--NB: I recommend using a JSON library instead of parsing and writing this by-hand.--The morphological realiser may return more than one output per sentence.-Indeed, we expect a JSON-formatted list (a) of lists (b), where each (b)-provides a number of candidate morphological realisations for a sentence in-(a). The list (a) must have the same length as the input because each item in-(a) is expected to correspond to a sentence from the input.--Notice that the morphological generator can choose to delete spaces or do other-orthographical tricks in between words:--\begin{verbatim}-[- ["la fille detestait les garcons"],-- ["c'est le garcon que la fille detestait"- ,"c'est les garcons que la fille detestait"]-]-\end{verbatim}--If your morphological software does not do this, you could wrap it with a-simple script.--\begin{code}--- | Extracts the lemmas from a list of uninflected sentences. This is used--- when the morphological generator is unavailable, doesn't work, etc.-sansMorph :: LemmaPlusSentence -> [String]-sansMorph = singleton . unwords . map lem- where- lem (LemmaPlus l _) = l---- | Converts a list of uninflected sentences into inflected ones by calling---- the third party software.--- FIXME: this doesn't actually support lists-of-results per input--- will need to work it out-inflectSentencesUsingCmd :: String -> [LemmaPlusSentence] -> IO [(LemmaPlusSentence,[String])]-inflectSentencesUsingCmd morphcmd sentences =- do -- run the inflector- (toP, fromP, _, _) <- runInteractiveCommand morphcmd- hPutStrLn toP . render . pp_value . showJSON $ sentences- hClose toP- -- read the inflector output back as a list of strings- mResults <- (resultToEither . decode) `fmap` hGetContents fromP- case mResults of- Left err -> fallback $ "Could not parse morphological generator output: " ++ err- Right res -> do let lenResults = length res- lenSentences = length sentences- if lenResults == lenSentences- then return $ zip sentences res- else fallback $ "Morphological generator returned "- ++ show lenResults ++ " results for "- ++ show lenSentences ++ " inputs"- `catch` \e -> fallback $ "Error calling morphological generator:\n" ++ show e- where- fallback err =- do ePutStrLn err- return $ map (\x -> (x, sansMorph x)) sentences--singleton :: a -> [a]-singleton x = [x]-\end{code}
+ src/NLP/GenI/Morphology/Types.hs view
@@ -0,0 +1,104 @@+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE DeriveDataTypeable #-}+-- GenI surface realiser+-- Copyright (C) 2005 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++module NLP.GenI.Morphology.Types where++import Control.Applicative ((<$>),(<*>))+import Control.DeepSeq+import Data.Text ( Text )++import NLP.GenI.GeniVal ( GeniVal )+import NLP.GenI.FeatureStructure ( Flist )+import NLP.GenI.Parser ( geniFeats, Parser, runParser )+import NLP.GenI.Pretty+import NLP.GenI.Semantics+import Text.JSON++-- ----------------------------------------------------------------------+-- morph input+-- ----------------------------------------------------------------------++type MorphInputFn = Literal GeniVal -> Maybe (Flist GeniVal)++-- ----------------------------------------------------------------------+-- morph output+-- ----------------------------------------------------------------------++type MorphRealiser = [LemmaPlusSentence] -> [MorphOutput]++data MorphOutput = MorphOutput { moWarnings :: [Text]+ , moRealisations :: [Text]+ }+ deriving (Ord, Eq)++instance JSON MorphOutput where+ readJSON j =+ case fromJSObject `fmap` readJSON j of+ Error _ -> MorphOutput [] <$> readJSON j+ Ok jo -> do+ let field x = maybe (fail $ "Could not find: " ++ x) readJSON+ $ lookup x jo+ warnings = maybe (return []) readJSON (lookup "warnings" jo)+ MorphOutput <$> warnings+ <*> field "realisations"+ showJSON _ = error "Don't know how to render MorphOutput"++-- | A lemma plus its morphological features+data LemmaPlus = LemmaPlus+ { lpLemma :: Text+ , lpFeats :: Flist GeniVal+ }+ deriving (Eq, Ord)++-- | A sentence composed of 'LemmaPlus' instead of plain old words+type LemmaPlusSentence = [LemmaPlus]++instance JSON LemmaPlus where+ readJSON j =+ do jo <- fromJSObject `fmap` readJSON j+ let field x = maybe (fail $ "Could not find: " ++ x) readJSON+ $ lookup x jo+ LemmaPlus <$> field "lemma"+ <*> (parsecToJSON "lemma-features" geniFeats =<< field "lemma-features")+ showJSON (LemmaPlus l fs) =+ JSObject . toJSObject $ [ ("lemma", showJSON l)+ , ("lemma-features", showJSON $ prettyStr fs)+ ]++parsecToJSON :: Monad m => String -> Parser b -> String -> m b+parsecToJSON description p str =+ case runParser p () "" str of+ Left err -> fail $ "Couldn't parse " ++ description ++ " because " ++ show err+ Right res -> return res++{-!+deriving instance NFData MorphOutput+deriving instance NFData LemmaPlus+!-}++-- GENERATED START++ +instance NFData MorphOutput where+ rnf (MorphOutput x1 x2) = rnf x1 `seq` rnf x2 `seq` ()++ +instance NFData LemmaPlus where+ rnf (LemmaPlus x1 x2) = rnf x1 `seq` rnf x2 `seq` ()+-- GENERATED STOP
+ src/NLP/GenI/OptimalityTheory.hs view
@@ -0,0 +1,343 @@+-- GenI surface realiser+-- Copyright (C) 2009 Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++{-# LANGUAGE OverloadedStrings #-}+module NLP.GenI.OptimalityTheory+ ( -- * Input+ OtConstraint(..), OtRanking,+ -- * Output+ GetTraces, OtResult, OtViolation, RankedOtConstraint(..),+ rankResults, otWarnings,+ -- * Display+ prettyViolations,prettyRank+ )+ where++import Control.Applicative ( (<$>), (<*>) )+import Control.Arrow ( first )+import Data.Function (on)+import Data.Char ( isSpace )+import Data.List (nub, partition, sort, sortBy, groupBy, (\\), unfoldr )+import Data.Text ( Text )+import qualified Data.Text as T+import Text.JSON++import NLP.GenI.Pretty+import NLP.GenI.TreeSchema ( Macros, ptrace )+import qualified NLP.GenI.Builder as B++import Control.DeepSeq++data OtConstraint = PositiveC Text -- ^ the trace must appear+ | NegativeC Text -- ^ the trace must NOT appear+ | NegativeConjC [Text] -- ^ these traces must not appear AT THE SAME TIME+ deriving (Show, Eq)++data RankedOtConstraint = RankedOtConstraint Int OtConstraint+ deriving (Show, Eq)++instance Ord RankedOtConstraint where+ compare (RankedOtConstraint r1 _) (RankedOtConstraint r2 _) = compare r1 r2++-- | Same as 'RankedOtConstraint' with the sorting inverted+newtype RankedOtConstraint2 = RankedOtConstraint2 RankedOtConstraint deriving Eq++instance Ord RankedOtConstraint2 where+ compare (RankedOtConstraint2 x) (RankedOtConstraint2 y) = compare y x+++type OtRanking = [[OtConstraint]]++data OtViolation = OtViolation { otLexName :: Text -- ^ empty for global+ , otConstraintViolated :: RankedOtConstraint }+ deriving (Show, Eq, Ord)++data LexItem = LexItem+ { lLexname :: Text+ , lTraces :: [Text]+ }+ deriving (Ord, Eq, Show)++type GetTraces = Text -> [Text]+type OtResult x = (Int,x,[OtViolation])++instance JSON OtConstraint where+ readJSON j =+ do jv <- fromJSObject `fmap` readJSON j+ case lookup "pos-constraint" jv of+ Just v -> PositiveC `fmap` readJSON v+ Nothing -> case lookup "neg-constraint" jv of+ Just v -> NegativeC `fmap` readJSON v+ Nothing -> case lookup "neg-conj-constraint" jv of+ Just v -> NegativeConjC `fmap` readJSONs v+ Nothing -> fail $ "Could not read OtConstraint"+ showJSON (PositiveC c) =+ JSObject . toJSObject $ [ ("pos-constraint", showJSON c ) ]+ showJSON (NegativeC c) =+ JSObject . toJSObject $ [ ("neg-constraint", showJSON c ) ]+ showJSON (NegativeConjC cs) =+ JSObject . toJSObject $ [ ("neg-conj-constraint", showJSONs cs ) ]++-- ---------------------------------------------------------------------+-- top level stuff+-- ---------------------------------------------------------------------+otWarnings :: Macros -> OtRanking -> [OtViolation] -> [Text]+otWarnings gram ranking blocks =+ addWarning neTraces neTracesW+ . addWarning nvConstraints nvConstraintsW+ $ []+ where+ addWarning xs w = if null xs then id else (w xs :)+ neTracesW xs = "these traces never appear in the grammar: " `T.append` T.unwords xs+ neTraces = nonExistentTraces gram ranking+ nvConstraintsW xs = "these constraints are never violated: "+ `T.append` T.unwords (map pretty xs)+ nvConstraints = neverViolated blocks ranking++rankResults :: GetTraces -> (a -> B.TagDerivation) -> OtRanking -> [a] -> [OtResult a] --changed type Derivation+rankResults getTraces getDerivation r = squish . sortResults . map addViolations+ where+ addViolations x = (x, getViolations x)+ getViolations = violations (concatRank r) . lexTraces getTraces . getDerivation+ squish = concat . zipWith applyRank [1..]+ applyRank i = map (\(x,vs) -> (i,x,vs))++-- ---------------------------------------------------------------------+-- detecting violations+-- ---------------------------------------------------------------------++violations :: [RankedOtConstraint] -> [LexItem] -> [OtViolation]+violations cs ls = posVs ls ++ negVs ls+ where+ negVs = concatMap (\l -> negViolations cs (lLexname l) (lTraces l))+ posVs = posViolations cs . concatMap lTraces++-- | A positive constraint is violated when a trace is NOT present+posViolations :: [RankedOtConstraint] -> [Text] -> [OtViolation]+posViolations cs ss =+ [ OtViolation "" c | c@(RankedOtConstraint _ (PositiveC s)) <- cs, not (s `elem` ss) ]++-- | A negative constraint is violated when a trace is present+--+-- Note that we will not notice if a constraint is violated more+-- than once. If you want to count multiple violations, you'll+-- either need to partition the input strings and map this function+-- on each sublist or rewrite this code.+negViolations :: [RankedOtConstraint]+ -> Text -- ^ lex name+ -> [Text] -- ^ traces+ -> [OtViolation]+negViolations cs l ss =+ [ OtViolation l c | c@(RankedOtConstraint _ (NegativeC s)) <- cs, s `elem` ss ] +++ [ OtViolation l c | c@(RankedOtConstraint _ (NegativeConjC xs)) <- cs, all (`elem` ss) xs ]++-- | Violations sorted so that the highest ranking constraint+-- (smallest number) goes first+sortedViolations :: (a, [OtViolation]) -> [RankedOtConstraint2]+sortedViolations = map (RankedOtConstraint2 . otConstraintViolated) . sort . snd++-- | Sort the sentences so that the ones with the *lowest*+-- ranking violations (biggest number) go first.+-- Note that we return in groups for the sake of ties.+sortResults :: [(a, [OtViolation])] -> [[(a, [OtViolation])]]+sortResults = sortAndGroupByDecoration compare sortedViolations++lexTraces :: GetTraces -> B.TagDerivation -> [LexItem] --changed type Derivation+lexTraces getTraces = map (toLexItem getTraces) . B.lexicalSelection++toLexItem :: GetTraces -> Text -> LexItem+toLexItem getTraces t =+ LexItem { lLexname = t+ , lTraces = getTraces t+ }++-- ----------------------------------------------------------------------+-- Output format+-- ----------------------------------------------------------------------++instance JSON RankedOtConstraint where+ readJSON j =+ do jo <- fromJSObject `fmap` readJSON j+ let field x = maybe (fail $ "Could not find: " ++ x) readJSON+ $ lookup x jo+ RankedOtConstraint <$> field "rank"+ <*> field "violation"+ showJSON = JSObject . toJSObject . rankedOtConstraintToPairs++rankedOtConstraintToPairs :: RankedOtConstraint -> [ (String, JSValue) ]+rankedOtConstraintToPairs (RankedOtConstraint r c) =+ [ ("rank", showJSON r), ("violation", showJSON c) ]++instance JSON OtViolation where+ readJSON j =+ do jo <- fromJSObject `fmap` readJSON j+ case lookup "lex-item" jo of+ Nothing -> OtViolation "" <$> readJSON j+ Just l -> OtViolation <$> readJSON l+ <*> readJSON j++ showJSON ov = JSObject . toJSObject $ pairs+ where+ pairs = case otLexName ov of+ "" -> basicPairs+ l -> ("lex-item", showJSON l) : basicPairs+ basicPairs = rankedOtConstraintToPairs (otConstraintViolated ov)++-- ---------------------------------------------------------------------+-- pretty printing+-- ---------------------------------------------------------------------++-- TODO: Return as a pretty Doc+prettyViolations :: GetTraces -> Bool -> [OtViolation] -> Text+prettyViolations getTraces noisy vs =+ T.unlines $+ [ indented 1 75 (showPosVs posVs) | not (null posVs) ]+ ++ map showLexVs negBuckets+ where+ (posVs, negVs) = partition (T.null . otLexName) vs+ negBuckets = buckets otLexName negVs+ --+ showPosVs = T.unwords . map prettyV+ showLexVs (l,lvs) =+ (indented 2 75 . T.unwords $ parens l : map prettyV lvs) `T.append`+ (if noisy then "\n" `T.append` allTraces l else "")+ where+ allTraces = indented 4 75 . T.unwords . getTraces+ prettyV = pretty . otConstraintViolated++instance Pretty RankedOtConstraint where+ pretty (RankedOtConstraint r c) = pretty c <+> prettyRank r++instance Pretty OtConstraint where+ pretty (PositiveC str) = '+' `T.cons` str+ pretty (NegativeC str) = '*' `T.cons` str+ pretty (NegativeConjC strs) =+ '*' `T.cons` (parens . T.intercalate " & " $ strs)++prettyRank :: Int -> Text+prettyRank r = parens $ 'r' `T.cons` T.pack (show r)++-- ---------------------------------------------------------------------+-- detecting impossible constraints or other potential errors+-- ---------------------------------------------------------------------++neverViolated :: [OtViolation] -> [[OtConstraint]] -> [OtConstraint]+neverViolated vs ranking = concat ranking \\ cs_used+ where+ cs_used = nub . map (noRank . otConstraintViolated) $ vs++nonExistentTraces :: Macros -> [[OtConstraint]] -> [Text]+nonExistentTraces ms vs = r_traces \\ m_traces+ where+ m_traces = nub $ concatMap ptrace ms+ r_traces = nub $ concatMap cTraces $ concat vs++cTraces :: OtConstraint -> [Text]+cTraces (PositiveC c) = [c]+cTraces (NegativeConjC cs) = cs+cTraces (NegativeC c) = [c]++-- ----------------------------------------------------------------------+-- helpers+-- ----------------------------------------------------------------------++concatRank :: [[OtConstraint]] -> [RankedOtConstraint]+concatRank = concat . zipWith rank [1..]+ where+ rank x ys = map (RankedOtConstraint x) ys++noRank :: RankedOtConstraint -> OtConstraint+noRank (RankedOtConstraint _ c) = c++-- ----------------------------------------------------------------------+-- odds and ends+-- ----------------------------------------------------------------------++buckets :: Ord b => (a -> b) -> [a] -> [ (b,[a]) ]+buckets f = map (first head . unzip)+ . groupBy ((==) `on` fst)+ . sortBy (compare `on` fst)+ . map (\x -> (f x, x))++-- | Results are grouped so that ties can be noticed+sortAndGroupByDecoration :: Eq b => (b -> b -> Ordering) -> (a -> b) -> [a] -> [[a]]+sortAndGroupByDecoration cmp f = map (map snd)+ . groupBy ((==) `on` fst)+ . sortBy (cmp `on` fst)+ . map (\x -> (f x, x))++indented :: Int -> Int -> Text -> Text+indented x len = T.intercalate "\n"+ . map (\s -> spaces x `T.append` s)+ . wordWrap len++spaces :: Int -> Text+spaces n = T.pack (replicate n ' ')++-- | Whitespace-sensitive wrapping+--+-- Properties:+--+-- * Only splits at whitespace+--+-- * Lines at most @len@ characters long, whitespace permitting+wordWrap :: Int -- ^ wrap after these many characters+ -> Text+ -> [Text]+wordWrap len =+ unfoldr f+ where+ f t = if T.null t then Nothing else Just (splitAtBefore len t)++splitAtBefore :: Int -- ^ wrap after these many characters + -> Text+ -> (Text, Text)+splitAtBefore len xs+ | T.length xs < len = (xs, "")+ | T.any isSpace xs = (begin, end)+ | otherwise = (xs, "")+ where+ begin =+ if T.length upToSpace > len+ then upToSpace -- ugh! that's one massive line+ else T.stripEnd . T.dropWhileEnd isNotSpace . T.take len $ xs+ end = T.stripStart $ T.drop (T.length begin) xs+ upToSpace = T.stripStart xs+ isNotSpace = not . isSpace++{-!+deriving instance NFData OtViolation+deriving instance NFData RankedOtConstraint+deriving instance NFData OtConstraint+!-}++-- GENERATED START++ +instance NFData OtViolation where+ rnf (OtViolation x1 x2) = rnf x1 `seq` rnf x2 `seq` ()++ +instance NFData RankedOtConstraint where+ rnf (RankedOtConstraint x1 x2) = rnf x1 `seq` rnf x2 `seq` ()++ +instance NFData OtConstraint where+ rnf (PositiveC x1) = rnf x1 `seq` ()+ rnf (NegativeC x1) = rnf x1 `seq` ()+ rnf (NegativeConjC x1) = rnf x1 `seq` ()+-- GENERATED STOP
− src/NLP/GenI/OptimalityTheory.lhs
@@ -1,390 +0,0 @@-% GenI surface realiser-% Copyright (C) 2009 Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.--\chapter{Ranking output}-\label{cha:ranking}--\begin{code}-module NLP.GenI.OptimalityTheory- ( -- * Input- OtConstraint(..), OtRanking,- -- * Output- GetTraces, OtResult, OtViolation, RankedOtConstraint(..),- rankResults, otWarnings,- -- * Display- prettyViolations,prettyRank- )- where--import Control.Applicative ( (<$>), (<*>) )-import Control.Arrow ( first )-import Data.Function (on)-import Data.Char ( isSpace )-import Data.List (nub, partition, sort, sortBy, groupBy, intersperse, (\\), unfoldr )-import Text.JSON--import NLP.GenI.Btypes ( Macros, ptrace )-import qualified NLP.GenI.Builder as B-\end{code}--If your tree schemata are annotated with traces (TODO link to traces and-metagrammars), you can re-use them as a basis for ranking the output produced-by GenI. The basic idea is to supply a list of either positive, negative or-negative conjunction constraints.--For users familiar with Haskell, the constraints are described with the-following type:-\begin{includecodeinmanual}-\begin{code}-data OtConstraint = PositiveC String -- ^ the trace must appear- | NegativeC String -- ^ the trace must NOT appear- | NegativeConjC [String] -- ^ these traces must not appear AT THE SAME TIME- deriving (Show, Eq)-\end{code}-\end{includecodeinmanual}--Roughly speaking the more highly ranked the constraint, the greater the impact-of a violation of that constraint will be. See section-\ref{sec:ranking-procedure} for more details on the ranking procedure.--\begin{code}-data RankedOtConstraint = RankedOtConstraint Int OtConstraint- deriving (Show, Eq)--instance Ord RankedOtConstraint where- compare (RankedOtConstraint r1 _) (RankedOtConstraint r2 _) = compare r1 r2---- | Same as 'RankedOtConstraint' with the sorting inverted-newtype RankedOtConstraint2 = RankedOtConstraint2 RankedOtConstraint deriving Eq--instance Ord RankedOtConstraint2 where- compare (RankedOtConstraint2 x) (RankedOtConstraint2 y) = compare y x---type OtRanking = [[OtConstraint]]--data OtViolation = OtViolation { otLexName :: String -- ^ empty for global- , otConstraintViolated :: RankedOtConstraint }- deriving (Show, Eq, Ord)--data LexItem = LexItem- { lLexname :: String- , lTraces :: [String]- } deriving (Ord, Eq, Show)--type GetTraces = String -> [String]-type OtResult x = (Int,x,[OtViolation])-\end{code}--\section{Input format}--Constraints are expressed in JSON as a list of \jargon{ranking levels}. A-ranking level is a list of constraints that should be assigned the same rank.-In lieu of a formal description, we provide an example below:-\small{NB: Either the JSON format or the JSON parser used by GenI is strict-enough to refuse initial whitespace in this file.}--\begin{verbatim}-[- [{"neg-constraint": "dian0Vn1dePassive"},- {"pos-constraint": "CanonicalSubject"}],-- [{"neg-conj-constraint": ["InvertedNominalSubject",- "CanonicalSententialObjectFinite"]}],-- [{"neg-conj-constraint": ["InvertedNominalSubject",- "UnboundedCleft"]},- {"neg-constraint": "CleftSubject"}]-]-\end{verbatim}--This example constraints file has three ranking levels. These levels contain-following constraints:--\begin{enumerate}-\item A negative constraint saying that \verb!dian0Vn1dePassive! should- not appear, and a positive one saying that \verb!CanonicalSubject!- \emph{should} appear. These constraints appear together only because- the author of the example thinks they should have the same rank,- not because there is neccesarily any inherent relationship between- them.-\item A single negative conjunction constraint saying that- \verb!InvertedNominalSubject! and- \verb!CanonicalSententialObjectFinite!- should not appear together.-\item A negative conjunction constraint saying tat- \verb!InvertedNominalSubject! and \verb!UnboundedCleft! should not- appear together; and also a negative constraints saying that- \verb!CleftSubject! should not appear. As with the first ranking- level, there is no relationship between these two constraints. We- just put them on the same level to give them the same rank-\end{enumerate}--\begin{code}-instance JSON OtConstraint where- readJSON j =- do jv <- fromJSObject `fmap` readJSON j- case lookup "pos-constraint" jv of- Just v -> PositiveC `fmap` readJSON v- Nothing -> case lookup "neg-constraint" jv of- Just v -> NegativeC `fmap` readJSON v- Nothing -> case lookup "neg-conj-constraint" jv of- Just v -> NegativeConjC `fmap` readJSONs v- Nothing -> fail $ "Could not read OtConstraint"- showJSON (PositiveC c) =- JSObject . toJSObject $ [ ("pos-constraint", showJSON c ) ]- showJSON (NegativeC c) =- JSObject . toJSObject $ [ ("neg-constraint", showJSON c ) ]- showJSON (NegativeConjC cs) =- JSObject . toJSObject $ [ ("neg-conj-constraint", showJSONs cs ) ]-\end{code}--\begin{code}--- ------------------------------------------------------------------------ top level stuff--- ----------------------------------------------------------------------otWarnings :: Macros -> OtRanking -> [OtViolation] -> [String]-otWarnings gram ranking blocks =- addWarning neTraces neTracesW- . addWarning nvConstraints nvConstraintsW- $ []- where- addWarning xs w = if null xs then id else (w xs :)- neTracesW xs = "these traces never appear in the grammar: " ++ unwords xs- neTraces = nonExistentTraces gram ranking- nvConstraintsW xs = "these constraints are never violated: " ++ unwords (map prettyConstraint xs)- nvConstraints = neverViolated blocks ranking--rankResults :: GetTraces -> (a -> B.Derivation) -> OtRanking -> [a] -> [OtResult a]-rankResults getTraces getDerivation r = squish . sortResults . map addViolations- where- addViolations x = (x, getViolations x)- getViolations = violations (concatRank r) . lexTraces getTraces . getDerivation- squish = concat . zipWith applyRank [1..]- applyRank i = map (\(x,vs) -> (i,x,vs))-\end{code}---\begin{code}--- ------------------------------------------------------------------------ detecting violations--- -----------------------------------------------------------------------violations :: [RankedOtConstraint] -> [LexItem] -> [OtViolation]-violations cs ls = posVs ls ++ negVs ls- where- negVs = concatMap (\l -> negViolations cs (lLexname l) (lTraces l))- posVs = posViolations cs . concatMap lTraces---- | A positive constraint is violated when a trace is NOT present-posViolations :: [RankedOtConstraint] -> [String] -> [OtViolation]-posViolations cs ss =- [ OtViolation "" c | c@(RankedOtConstraint _ (PositiveC s)) <- cs, not (s `elem` ss) ]---- | A negative constraint is violated when a trace is present------ Note that we will not notice if a constraint is violated more--- than once. If you want to count multiple violations, you'll--- either need to partition the input strings and map this function--- on each sublist or rewrite this code.-negViolations :: [RankedOtConstraint]- -> String -- ^ lex name- -> [String] -- ^ traces- -> [OtViolation]-negViolations cs l ss =- [ OtViolation l c | c@(RankedOtConstraint _ (NegativeC s)) <- cs, s `elem` ss ] ++- [ OtViolation l c | c@(RankedOtConstraint _ (NegativeConjC xs)) <- cs, all (`elem` ss) xs ]-\end{code}--\section{Ranking procedure}-\label{sec:ranking-procedure}--Generation results are sorted according to their highest-ranking constraint-violation (moving on to the next-highest ranking violation and so forth in case-of a tie). The best result appears first.--\begin{code}--- | Violations sorted so that the highest ranking constraint--- (smallest number) goes first-sortedViolations :: (a, [OtViolation]) -> [RankedOtConstraint2]-sortedViolations = map (RankedOtConstraint2 . otConstraintViolated) . sort . snd---- | Sort the sentences so that the ones with the *lowest*--- ranking violations (biggest number) go first.--- Note that we return in groups for the sake of ties.-sortResults :: [(a, [OtViolation])] -> [[(a, [OtViolation])]]-sortResults = sortAndGroupByDecoration compare sortedViolations--lexTraces :: GetTraces -> B.Derivation -> [LexItem]-lexTraces getTraces = map (toLexItem getTraces) . B.lexicalSelection--toLexItem :: GetTraces -> String -> LexItem-toLexItem getTraces t =- LexItem { lLexname = t- , lTraces = getTraces t }-\end{code}--\section{Output format}--Constraint violations can be outputted as JSON objects as the following example-shows--\begin{verbatim}- { "lex-item": "discuter:n0Vn1pn2:Tn0Vn1pn2-5830:22",- , "rank": 6,- , "violation": {"neg-constraint": "passiveVerbMorphology"}- }-\end{verbatim}--Positive constraint violations are not associated with any lexical items-so the lex-item field is omitted for them.--\begin{code}--- ------------------------------------------------------------------------ output--- ----------------------------------------------------------------------instance JSON RankedOtConstraint where- readJSON j =- do jo <- fromJSObject `fmap` readJSON j- let field x = maybe (fail $ "Could not find: " ++ x) readJSON- $ lookup x jo- RankedOtConstraint <$> field "rank"- <*> field "violation"- showJSON = JSObject . toJSObject . rankedOtConstraintToPairs--rankedOtConstraintToPairs :: RankedOtConstraint -> [ (String, JSValue) ]-rankedOtConstraintToPairs (RankedOtConstraint r c) =- [ ("rank", showJSON r), ("violation", showJSON c) ]--instance JSON OtViolation where- readJSON j =- do jo <- fromJSObject `fmap` readJSON j- case lookup "lex-item" jo of- Nothing -> OtViolation "" <$> readJSON j- Just l -> OtViolation <$> readJSON l- <*> readJSON j-- showJSON ov = JSObject . toJSObject $ pairs- where- pairs = case otLexName ov of- "" -> basicPairs- l -> ("lex-item", showJSON l) : basicPairs- basicPairs = rankedOtConstraintToPairs (otConstraintViolated ov)---- ------------------------------------------------------------------------ pretty printing--- ------------------------------------------------------------------------- TODO: Return as a pretty Doc-prettyViolations :: GetTraces -> Bool -> [OtViolation] -> String-prettyViolations getTraces noisy vs =- unlines $ (if null posVs then [] else [ indented 1 75 . showPosVs $ posVs ])- ++ map showLexVs negBuckets- where- (posVs, negVs) = partition (null . otLexName) vs- negBuckets = buckets otLexName negVs- --- showPosVs = unwords . map (prettyRankedConstraint . otConstraintViolated)- showLexVs (l,lvs) =- let itmName = "(" ++ l ++ ")"- constraints = map otConstraintViolated lvs- allTraces = indented 4 75 . unwords . getTraces $ l- in (indented 2 75 . unwords $ itmName : map prettyRankedConstraint constraints)- ++ (if noisy then "\n" ++ allTraces else "")--prettyRankedConstraint :: RankedOtConstraint -> String-prettyRankedConstraint (RankedOtConstraint r c) = prettyConstraint c ++ " " ++ prettyRank r--prettyConstraint :: OtConstraint -> String-prettyConstraint (PositiveC str) = '+' : str-prettyConstraint (NegativeC str) = '*' : str-prettyConstraint (NegativeConjC strs) = "*(" ++ (concat $ intersperse " & " strs) ++ ")"--prettyRank :: Int -> String-prettyRank r = "(r" ++ show r ++ ")"---- ------------------------------------------------------------------------ detecting impossible constraints or other potential errors--- -----------------------------------------------------------------------neverViolated :: [OtViolation] -> [[OtConstraint]] -> [OtConstraint]-neverViolated vs ranking = concat ranking \\ cs_used- where- cs_used = nub . map (noRank . otConstraintViolated) $ vs--nonExistentTraces :: Macros -> [[OtConstraint]] -> [String]-nonExistentTraces ms vs = r_traces \\ m_traces- where- m_traces = nub $ concatMap ptrace ms- r_traces = nub $ concatMap cTraces $ concat vs--cTraces :: OtConstraint -> [String]-cTraces (PositiveC c) = [c]-cTraces (NegativeConjC cs) = cs-cTraces (NegativeC c) = [c]---- ------------------------------------------------------------------------- helpers--- ------------------------------------------------------------------------concatRank :: [[OtConstraint]] -> [RankedOtConstraint]-concatRank = concat . zipWith rank [1..]- where- rank x ys = map (RankedOtConstraint x) ys--noRank :: RankedOtConstraint -> OtConstraint-noRank (RankedOtConstraint _ c) = c---- ------------------------------------------------------------------------- odds and ends--- ------------------------------------------------------------------------buckets :: Ord b => (a -> b) -> [a] -> [ (b,[a]) ]-buckets f = map (first head . unzip)- . groupBy ((==) `on` fst)- . sortBy (compare `on` fst)- . map (\x -> (f x, x))---- | Results are grouped so that ties can be noticed-sortAndGroupByDecoration :: Eq b => (b -> b -> Ordering) -> (a -> b) -> [a] -> [[a]]-sortAndGroupByDecoration cmp f = map (map snd)- . groupBy ((==) `on` fst)- . sortBy (cmp `on` fst)- . map (\x -> (f x, x))--indented :: Int -> Int -> String -> String-indented x len = concat . intersperse "\n" . map (\s -> spaces x ++ s) . unfoldr f- where- f "" = Nothing- f str = Just $ splitAtBefore len str--spaces :: Int -> String-spaces n = replicate n ' '--splitAtBefore :: Int -> String -> (String, String)-splitAtBefore len xs- | length xs < len = (xs, "")- | any isSpace xs = (begin, trim $ drop (length begin) xs)- | otherwise = (xs, "")- where- begin- | length upToSpace > len = upToSpace- | otherwise = reverse . trim . dropWhile isNotSpace . reverse . take len $ xs- upToSpace = takeWhile isNotSpace xs- isNotSpace = not . isSpace- trim = drop 1-\end{code}
+ src/NLP/GenI/Parser.hs view
@@ -0,0 +1,633 @@+-- GenI surface realiser+-- Copyright (C) 2005 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++{-# LANGUAGE CPP, FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}+module NLP.GenI.Parser (+ -- * Test suites+ geniTestSuite, geniSemanticInput, geniTestSuiteString,+ geniDerivations,+ toSemInputString,+ -- * Trees+ geniMacros, geniTagElems,+ -- * Lexicon and morph+ geniLexicon, geniMorphInfo,+ -- * Basics+ geniFeats, geniSemantics, geniValue, geniWords,+ -- * Helpers+ geniWord, geniLanguageDef, tillEof,+ --+ parseFromFile, -- UTF-8 version+ module Text.Parsec,+ module Text.Parsec.String,+) where+++import Control.Applicative ( (<*>), (<$>), (*>), (<*) )+import Control.Monad (liftM, when)+import Data.Text ( Text )+import Text.Parsec+import Text.Parsec.String hiding ( parseFromFile ) -- TODO: replace with Text.Parsec.Text+import Text.Parsec.Language (emptyDef)+import Text.Parsec.Token (TokenParser,+ LanguageDef,+ commentLine, commentStart, commentEnd, opLetter,+ reservedOpNames, reservedNames, identLetter, identStart, + makeTokenParser)+import qualified Data.Map as Map+import qualified Data.Text as T+import qualified Data.Tree as T+import qualified System.IO.UTF8 as UTF8+--import qualified Text.Parsec.Expr as P+import qualified Text.Parsec.Token as P++import NLP.GenI.FeatureStructure ( Flist, AvPair(..), sortFlist )+import NLP.GenI.General (isGeniIdentLetter)+import NLP.GenI.GeniShow ( GeniShow(..), geniKeyword )+import NLP.GenI.GeniVal ( GeniVal, mkGConst, mkGConstNone, mkGVar, mkGAnon, isAnon )+import NLP.GenI.Lexicon ( fromLexSem, mkFullLexEntry, LexEntry(..) )+import NLP.GenI.Pretty ( above )+import NLP.GenI.Semantics ( Literal(..), Sem, sortSem, LitConstr, SemInput )+import NLP.GenI.Tag (TagElem(..), setTidnums)+import NLP.GenI.TestSuite ( TestCase(..) )+import NLP.GenI.TreeSchema (SchemaTree, Ttree(..), Ptype(..), GNode(..), GType(..) )++-- import BoolExp+import Data.FullList ( FullList, Listable(..) )+++-- General notes++-- reserved words+#define SEMANTICS "semantics"+#define SENTENCE "sentence"+#define OUTPUT "output"+#define TRACE "trace"+#define ANCHOR "anchor"+#define SUBST "subst"+#define FOOT "foot"+#define LEX "lex"+#define TYPE "type"+#define ACONSTR "aconstr"+#define INITIAL "initial"+#define AUXILIARY "auxiliary"+#define IDXCONSTRAINTS "idxconstraints"+#define BEGIN "begin"+#define END "end"++-- Lexer++geniLanguageDef :: LanguageDef ()+geniLanguageDef = emptyDef+ { commentLine = "%"+ , commentStart = "/*"+ , commentEnd = "*/"+ , opLetter = oneOf ""+ , reservedOpNames = [""]+ , reservedNames =+ [ SEMANTICS , SENTENCE, OUTPUT, IDXCONSTRAINTS, TRACE+ , ANCHOR , SUBST , FOOT , LEX , TYPE , ACONSTR+ , INITIAL , AUXILIARY+ , BEGIN , END ]+ , identLetter = identStuff+ , identStart = identStuff+ }+ where identStuff = satisfy isGeniIdentLetter++geniValue :: Parser GeniVal+geniValue = ((try $ anonymous) <?> "_ or ?_")+ <|> (constants <?> "a constant or atomic disjunction")+ <|> (variable <?> "a variable")+ where+ question = "?"+ disjunction = geniAtomicDisjunction+ constants :: Parser GeniVal+ constants = mkGConst <$> disjunction+ variable :: Parser GeniVal+ variable =+ do symbol question+ v <- identifier+ mcs <- option Nothing $ (symbol "/" >> Just `liftM` disjunction)+ return (mkGVar v mcs)+ anonymous :: Parser GeniVal+ anonymous =+ do optional $ symbol question+ symbol "_"+ return mkGAnon++geniAtomicDisjunction :: Parser (FullList Text)+geniAtomicDisjunction = do+ (x:xs) <- atom `sepBy1` (symbol "|")+ return (x !: xs)+ where+ atom = looseIdentifier <|> stringLiteral++geniFancyDisjunction :: Parser [GeniVal]+geniFancyDisjunction = geniValue `sepBy1` symbol ";"++class GeniValLike v where+ geniValueLike :: Parser v++instance GeniValLike GeniVal where+ geniValueLike = geniValue++instance GeniValLike [GeniVal] where+ geniValueLike = geniFancyDisjunction++-- We make no attempt to check for / guarantee uniqueness here+-- because the same sort of format is used for things which are+-- not strictly speaking feature structures+geniFeats :: GeniValLike v => Parser (Flist v)+geniFeats = option [] $ squares $ many geniAttVal++geniAttVal :: GeniValLike v => Parser (AvPair v)+geniAttVal = do+ att <- identifierR <?> "an attribute"; colon+ val <- geniValueLike <?> "a GenI value"+ return $ AvPair att val++geniSemantics :: Parser Sem+geniSemantics =+ do sem <- many (geniLiteral <?> "a literal")+ return (sortSem sem)++geniLiteral :: Parser (Literal GeniVal)+geniLiteral = geniLiteral_ mkGAnon geniValue++geniLiteral_ :: a -> Parser a -> Parser (Literal a)+geniLiteral_ zero gv =+ Literal <$> (option zero handleParser <?> "a handle")+ <*> (gv <?> "a predicate")+ <*> (parens (many gv) <?> "some parameters")+ where+ handleParser = try $ gv <* char ':'++geniSemanticInput :: Parser (Sem,Flist GeniVal,[LitConstr])+geniSemanticInput =+ do keywordSemantics+ (sem,litC) <- liftM unzip $ squares $ many literalAndConstraint+ idxC <- option [] geniIdxConstraints+ --+ let sem2 = createHandles sem+ semlitC2 = [ (s,c) | (s,c) <- zip sem2 litC, (not.null) c ]+ return (createHandles sem, idxC, semlitC2)+ where+ -- set all anonymous handles to some unique value+ -- this is to simplify checking if a result is+ -- semantically complete+ createHandles :: Sem -> Sem+ createHandles = zipWith setHandle ([1..] :: [Int])+ --+ setHandle i (Literal h pred_ par) =+ let h2 = if isAnon h+ then mkGConstNone ("genihandle" `T.append` T.pack (show i))+ else h+ in Literal h2 pred_ par+ --+ literalAndConstraint :: Parser LitConstr+ literalAndConstraint =+ do l <- geniLiteral+ t <- option [] $ squares $ many identifier+ return (l,t)++-- | The original string representation of the semantics (for gui)+geniSemanticInputString :: Parser Text+geniSemanticInputString = do+ keywordSemantics+ s <- squaresString+ whiteSpace+ optional geniIdxConstraints+ return s++geniIdxConstraints :: Parser (Flist GeniVal)+geniIdxConstraints = keyword IDXCONSTRAINTS >> geniFeats++{-+geniLitConstraints :: Parser (BoolExp T.Text)+geniLitConstraints =+ P.buildExpressionParser table piece+ where+ piece = (Cond <$> identifier)+ <|> do { string "~"; Not `liftM` geniLitConstraints }+ <|> parens geniLitConstraints+ table = [ [ op "&" And P.AssocLeft ]+ , [ op "|" Or P.AssocLeft ]+ ]+ op s f assoc = P.Infix (do { string s ; return f }) assoc+-}++squaresString :: Parser Text+squaresString = do+ char '['+ s <- (T.concat <$> many inSq) <|> squaresString+ char ']'+ return $ "[" `T.append` s `T.append` "]"+ where+ inSq :: Parser Text+ inSq = T.pack <$> many1 (noneOf "[]")++-- the output end of things+-- displaying preformatted semantic input++data SemInputString = SemInputString Text (Flist GeniVal)++instance GeniShow SemInputString where+ geniShowText (SemInputString semStr idxC) =+ geniKeyword SEMANTICS semStr `above` r+ where+ r | null idxC = ""+ | otherwise = geniKeyword IDXCONSTRAINTS (geniShowText idxC)++toSemInputString :: SemInput -> Text -> SemInputString+toSemInputString (_,lc,_) s = SemInputString s lc++geniTestSuite :: Parser [TestCase]+geniTestSuite =+ tillEof (many geniTestCase)++-- | Just the String representations of the semantics+-- in the test suite+geniTestSuiteString :: Parser [Text]+geniTestSuiteString =+ tillEof (many geniTestCaseString)++-- | This is only used by the script genimakesuite+geniDerivations :: Parser [TestCaseOutput]+geniDerivations = tillEof $ many geniOutput++geniTestCase :: Parser TestCase+geniTestCase =+ TestCase <$> (option "" (identifier <?> "a test case name"))+ <*> lookAhead geniSemanticInputString+ <*> geniSemanticInput+ <*> many geniSentence++-- note that the keyword is NOT optional+type TestCaseOutput = (Text, Map.Map (Text,Text) [Text])+geniOutput :: Parser TestCaseOutput+geniOutput = do+ ws <- keyword OUTPUT >> squares geniWords+ ds <- Map.fromList <$> many geniTraces+ return (ws, ds)++geniTraces :: Parser ((Text,Text), [Text])+geniTraces = do+ keyword TRACE+ squares $ do+ k1 <- withWhite geniWord+ k2 <- withWhite geniWord+ whiteSpace >> char '!' >> whiteSpace+ traces <- geniWord `sepEndBy1` whiteSpace+ return ((k1,k2), traces)++withWhite :: Parser a -> Parser a+withWhite p = p >>= (\a -> whiteSpace >> return a)++geniSentence :: Parser Text+geniSentence = optional (keyword SENTENCE) >> squares geniWords++geniWords :: Parser Text+geniWords =+ T.unwords <$> (sepEndBy1 geniWord whiteSpace <?> "a sentence")++geniWord :: Parser Text+geniWord = T.pack <$> many1 (noneOf "[]\v\f\t\r\n ")++-- | The original string representation of a test case semantics+-- (for gui)+geniTestCaseString :: Parser Text+geniTestCaseString = do+ option "" (identifier <?> "a test case name")+ geniSemanticInputString <* (many geniSentence >> many geniOutput)++-- ----------------------------------------------------------------------+-- Lexicon+-- ----------------------------------------------------------------------++geniLexicon :: Parser [LexEntry]+geniLexicon = tillEof $ many1 geniLexicalEntry++geniLexicalEntry :: Parser LexEntry+geniLexicalEntry =+ do lemmas <- geniAtomicDisjunction <?> "a lemma (or disjunction thereof)"+ family <- identifier <?> "a tree family"+ (pars, interface) <- option ([],[]) $ parens paramsParser+ equations <- option [] $ do keyword "equations"+ geniFeats <?> "path equations"+ filters <- option [] $ do keyword "filters"+ geniFeats+ keywordSemantics+ (sem, pols) <- fromLexSem <$> squares geniLexSemantics+ --+ return (mkFullLexEntry lemmas family pars interface filters equations sem pols)+ where+ paramsParser :: Parser ([GeniVal], Flist GeniVal)+ paramsParser = do+ pars <- many geniValue <?> "some parameters"+ interface <- option [] $ do symbol "!"+ many geniAttVal+ return (pars, interface)++geniLexSemantics :: Parser [Literal PolValue]+geniLexSemantics = sortSem <$> many (geniLexLiteral <?> "a literal")++type PolValue = (GeniVal, Int)++geniLexLiteral :: Parser (Literal PolValue)+geniLexLiteral = geniLiteral_ (mkGAnon,0) geniPolValue++geniPolValue :: Parser (GeniVal, Int)+geniPolValue =+ do p <- geniPolarity+ v <- geniValue+ return (v,p)++-- ----------------------------------------------------------------------+-- Tree schemata+-- ----------------------------------------------------------------------++geniMacros :: Parser [SchemaTree]+geniMacros = tillEof $ many geniTreeDef++initType, auxType :: Parser Ptype+initType = do { reserved INITIAL ; return Initial }+auxType = do { reserved AUXILIARY ; return Auxiliar }++geniTreeDef :: Parser SchemaTree+geniTreeDef =+ do sourcePos <- getPosition+ family <- identifier+ tname <- option "" (colon *> identifier)+ (pars,iface) <- geniParams+ theTtype <- (initType <|> auxType)+ theTree <- geniTree+ -- sanity checks?+ let treeFail x =+ do setPosition sourcePos -- FIXME does not do what I expect+ fail $ "In tree " ++ T.unpack family ++ ":"+ ++ T.unpack tname ++ " " ++ show sourcePos ++ ": " ++ x+ let theNodes = T.flatten theTree+ numFeet = length [ x | x <- theNodes, gtype x == Foot ]+ numAnchors = length [ x | x <- theNodes, ganchor x ]+ when (not $ any ganchor theNodes) $+ treeFail "At least one node in an LTAG tree must be an anchor"+ when (numAnchors > 1) $+ treeFail "There can be no more than 1 anchor node in a tree"+ when (numFeet > 1) $+ treeFail "There can be no more than 1 foot node in a tree"+ when (theTtype == Initial && numFeet > 0) $+ treeFail "Initial trees may not have foot nodes"+ --+ psem <- option Nothing $ do { keywordSemantics; liftM Just (squares geniSemantics) }+ ptrc <- option [] $ do { keyword TRACE; squares (many identifier) }+ --+ return TT{ params = pars+ , pfamily = family+ , pidname = tname+ , pinterface = sortFlist iface+ , ptype = theTtype+ , tree = theTree+ , ptrace = ptrc+ , psemantics = psem+ }++geniTree :: (Ord v, GeniValLike v) => Parser (T.Tree (GNode v))+geniTree =+ do node <- geniNode+ kids <- option [] (braces $ many geniTree)+ <?> "child nodes"+ -- sanity checks+ let noKidsAllowed t c = when (c node && (not.null $ kids)) $+ fail $ t ++ " nodes may *not* have any children"+ noKidsAllowed "Anchor" $ ganchor+ noKidsAllowed "Substitution" $ (== Subs) . gtype+ noKidsAllowed "Foot" $ (== Foot) . gtype+ --+ return (T.Node node kids)++geniNode :: (Ord v, GeniValLike v) => Parser (GNode v)+geniNode = do+ name <- identifier+ nodeType <- geniNodeAnnotation+ lex_ <- if nodeType == AnnoLexeme+ then ((stringLiteral <|> identifier) `sepBy` symbol "|") <?> "some lexemes"+ else return []+ constr <- case nodeType of+ AnnoDefault -> adjConstraintParser+ AnnoAnchor -> adjConstraintParser+ _ -> return True+ -- features only obligatory for non-lex nodes+ (top,bot) <- if nodeType == AnnoLexeme+ then option ([],[]) $ try topbotParser+ else topbotParser+ return $ GN { gnname = name+ , gtype = fromAnnotation nodeType+ , gup = sortFlist top+ , gdown = sortFlist bot+ , glexeme = lex_+ , ganchor = nodeType == AnnoAnchor+ , gaconstr = constr+ , gorigin = ""+ }+ where+ adjConstraintParser = option False $ reserved ACONSTR >> char ':' >> symbol "noadj" >> return True+ topbotParser = do+ top <- geniFeats <?> "top features"+ symbol "!"+ bot <- geniFeats <?> "bot features"+ return (top,bot)++-- | Should be purely internal type to help parsing.+-- Injection to 'GType'.+--+-- We don't just use GType directly because the annotations convey+-- subtle distinctions that aren't encoded, particularly between+-- lexemes and anchors+data Annotation = AnnoAnchor+ | AnnoLexeme+ | AnnoSubst+ | AnnoFoot+ | AnnoDefault+ deriving Eq++fromAnnotation :: Annotation -> GType+fromAnnotation AnnoLexeme = Lex+fromAnnotation AnnoAnchor = Lex+fromAnnotation AnnoSubst = Subs+fromAnnotation AnnoFoot = Foot+fromAnnotation AnnoDefault = Other++geniNodeAnnotation :: Parser Annotation+geniNodeAnnotation =+ (keyword TYPE *> ty) <|>+ (reserved ANCHOR >> return AnnoAnchor) <|>+ return AnnoDefault+ where+ ty = choice [ try (symbol s) >> return t | (s,t) <- table ]+ table =+ [ (ANCHOR, AnnoAnchor)+ , (FOOT, AnnoFoot)+ , (SUBST, AnnoSubst)+ , (LEX, AnnoLexeme)+ ]++-- | This makes it possible to read anchored trees, which may be+-- useful for debugging purposes.+--+-- FIXME: note that this is very rudimentary; we do not set id numbers,+-- parse polarities. You'll have to call+-- some of our helper functions if you want that functionality.+geniTagElems :: Parser [TagElem]+geniTagElems = tillEof $ setTidnums `fmap` many geniTagElem++geniTagElem :: Parser TagElem+geniTagElem = do+ family <- identifier+ tname <- option "" $ (colon *> identifier)+ iface <- (snd `liftM` geniParams) <|> geniFeats+ theType <- initType <|> auxType+ theTree <- geniTree+ sem <- do { keywordSemantics; squares geniSemantics }+ --+ return $ TE { idname = tname+ , ttreename = family+ , tinterface = iface+ , ttype = theType+ , ttree = theTree+ , tsemantics = sem+ , tidnum = -1 -- provisional id+ , tpolarities = Map.empty+ , tsempols = []+ , ttrace = []+ }++-- | 'geniParams' recognises a list of parameters optionally followed by a+-- bang (\verb$!$) and a list of attribute-value pairs. This whole thing is+-- to wrapped in the parens.+--+-- TODO: deprecate+geniParams :: Parser ([GeniVal], Flist GeniVal)+geniParams = parens $ do+ pars <- many geniValue <?> "some parameters"+ interface <- option [] $ do { symbol "!"; many geniAttVal }+ return (pars, interface)++-- ----------------------------------------------------------------------+-- Morphology+-- ----------------------------------------------------------------------++geniMorphInfo :: Parser [(Text,Flist GeniVal)]+geniMorphInfo = tillEof $ many morphEntry++morphEntry :: Parser (Text,Flist GeniVal)+morphEntry = (,) <$> identifier <*> geniFeats++-- ======================================================================+-- Everything else+-- ======================================================================++-- ----------------------------------------------------------------------+-- Polarities+-- ----------------------------------------------------------------------++-- | 'geniPolarity' associates a numerical value to a polarity symbol,+-- that is, '+' or '-'.+geniPolarity :: Parser Int+geniPolarity = option 0 (plus <|> minus)+ where+ plus = do { char '+'; return 1 }+ minus = do { char '-'; return (-1) }++-- ----------------------------------------------------------------------+-- keyword+-- ----------------------------------------------------------------------++{-# INLINE keyword #-}+keyword :: Text -> Parser Text+keyword k =+ (try $ do { reserved k; colon; return k }) <?> T.unpack k ++ ":"++{-# INLINE keywordSemantics #-}+keywordSemantics :: Parser Text+keywordSemantics = keyword SEMANTICS++-- ----------------------------------------------------------------------+-- language def helpers+-- ----------------------------------------------------------------------++lexer :: TokenParser ()+lexer = makeTokenParser geniLanguageDef++whiteSpace :: Parser ()+whiteSpace = P.whiteSpace lexer++identifier :: Parser Text+identifier = decode <$> P.identifier lexer++-- stolen from Parsec code (ident)+-- | Like 'identifier' but allows for reserved words too+looseIdentifier :: Parser Text+looseIdentifier =+ decode <$> do { i <- ident ; whiteSpace; return i }+ where+ ident = do+ { c <- identStart geniLanguageDef+ ; cs <- many (identLetter geniLanguageDef)+ ; return (c:cs) } <?> "identifier"++colon :: Parser Text+colon = decode <$> P.colon lexer++stringLiteral :: Parser Text+stringLiteral = decode <$> P.stringLiteral lexer++squares, braces, parens :: Parser a -> Parser a+squares = P.squares lexer+braces = P.braces lexer+parens = P.parens lexer++reserved :: Text -> Parser Text+reserved s = P.reserved lexer (T.unpack s) >> return s++symbol :: Text -> Parser Text+symbol s = P.symbol lexer (T.unpack s) >> return s++decode :: String -> Text+decode = T.pack++-- ----------------------------------------------------------------------+-- parsec helpers+-- ----------------------------------------------------------------------++-- | identifier, permitting reserved words too+identifierR :: Parser Text+identifierR = decode <$> do+ { c <- P.identStart geniLanguageDef+ ; cs <- many (P.identLetter geniLanguageDef)+ ; return (c:cs)+ } <?> "identifier or reserved word"++tillEof :: Parser a -> Parser a+tillEof p = whiteSpace *> p <* eof++-- stolen from Parsec and adapted to use UTF-8 input+parseFromFile :: Parser a -> SourceName -> IO (Either ParseError a)+parseFromFile p fname+ = do{ input <- UTF8.readFile fname+ ; return (parse p fname input)+ }
+ src/NLP/GenI/Polarity.hs view
@@ -0,0 +1,572 @@+-- GenI surface realiser+-- Copyright (C) 2009 Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++{-# LANGUAGE OverloadedStrings #-}+module NLP.GenI.Polarity(+ module NLP.GenI.Polarity.Types,++ -- * Entry point+ PolAut, PolState(PolSt), AutDebug, PolResult(..),+ buildAutomaton,++ -- * Inner stuff (exported for debugging?)+ makePolAut,+ fixPronouns,+ detectSansIdx, suggestPolFeatures, detectPols, detectPolPaths,+ declareIdxConstraints, detectIdxConstraints,+ prettyPolPaths, prettyPolPaths',++ -- re-exported from Automaton+ automatonPaths, finalSt,+ NFA(states, transitions),+ )+where++import Data.Bits+import qualified Data.Set as Set+import qualified Data.Map as Map+import Data.List+import Data.Maybe (isNothing, isJust)+import Data.Text (Text)+import qualified Data.Text as T++import NLP.GenI.Automaton+import NLP.GenI.FeatureStructure ( Flist, AvPair(..), FeatStruct, unifyFeat )+import NLP.GenI.General+ ( BitVector, isEmptyIntersect, thd3, Interval, ival, (!+!)+ )+import NLP.GenI.GeniVal ( GeniVal(gConstraints), mkGAnon, isAnon, replace )+import NLP.GenI.Polarity.Internal+import NLP.GenI.Polarity.Types+import NLP.GenI.Pretty+import NLP.GenI.Semantics ( Literal(..), SemInput, Sem, emptyLiteral+ , sortSem+ )+import NLP.GenI.Tag ( TagElem(..), TagItem(..), setTidnums )+import NLP.GenI.TreeSchema ( Ptype(Initial), GNode, root, gup, gdown, rootUpd)++-- ----------------------------------------------------------------------+-- Interface+-- ----------------------------------------------------------------------++-- | intermediate auts, seed aut, final aut, potentially modified sem+data PolResult = PolResult { prIntermediate :: [AutDebug]+ , prInitial :: PolAut+ , prFinal :: PolAut+ , prSem :: Sem }+type AutDebug = (PolarityKey, PolAut, PolAut)++-- | Constructs a polarity automaton. For debugging purposes, it returns+-- all the intermediate automata produced by the construction algorithm.+buildAutomaton :: Set.Set PolarityAttr -- ^ polarities to detect (eg. "cat")+ -> FeatStruct GeniVal -- ^ root features to compensate for+ -> PolMap -- ^ explicit extra polarities+ -> SemInput -- ^ input semantics+ -> [TagElem] -- ^ lexical selection+ -> PolResult+buildAutomaton polarityAttrs rootFeat extrapol (tsem,tres,_) candRaw =+ let -- root categories, index constraints, and external polarities+ rcatPol :: PolMap+ rcatPol = detectRootCompensation polarityAttrs rootFeat+ -- index constraints on candidate trees+ detect = detectIdxConstraints tres+ constrain t = t { tpolarities = Map.unionWith (!+!) p r+ } --, tinterface = [] }+ where p = tpolarities t+ r = detect . tinterface $ t+ candRest = map constrain candRaw+ inputRest = declareIdxConstraints tres+ -- polarity detection + cand1 = map (detectPols polarityAttrs) candRest+ extras1 = Map.unionsWith (!+!) [ extrapol, inputRest, rcatPol ]+ ks1 = polarityKeys cand1 Map.empty+ -- expanding unconstrained polarities+ tconvert t = t { tpolarities = convertUnconstrainedPolarities ks1 (tpolarities t) }+ cand = map tconvert cand1+ extras = convertUnconstrainedPolarities ks1 extras1+ ks = polarityKeys cand extras+ -- building the automaton+ in makePolAut cand tsem extras ks++makePolAut :: [TagElem] -> Sem -> PolMap -> [PolarityKey] -> PolResult+makePolAut candsRaw tsemRaw extraPol ks =+ let -- perform index counting+ (tsem, cands') = fixPronouns (tsemRaw,candsRaw)+ cands = setTidnums cands'+ -- sorted semantics (for more efficient construction)+ sortedsem = sortSemByFreq tsem cands + -- the seed automaton+ smap = buildColumns cands sortedsem + seed = buildSeedAut smap sortedsem+ -- building and remembering the automata + build k xs = (k,aut,prune aut):xs+ where aut = buildPolAut k initK (thd3 $ head xs)+ initK = Map.findWithDefault (ival 0) k extraPol+ res = foldr build [(PolarityKeyStr "(seed)",seed,prune seed)] ks+ in PolResult { prIntermediate = reverse res+ , prInitial = seed+ , prFinal = thd3 $ head res+ , prSem = tsem }++-- ====================================================================+-- Polarity automaton+-- ====================================================================++-- | Note: this is not the same function as 'NLP.GenI.Tags.mapBySem'!+-- The fact that we+-- preserve the order of the input semantics is important for our handling+-- of multi-literal semantics and for semantic frequency sorting.+buildColumns :: (TagItem t) => [t]+ -> Sem+ -> Map.Map (Literal GeniVal) [t]+buildColumns cands [] = + Map.singleton emptyLiteral e+ where e = filter (null.tgSemantics) cands++buildColumns cands (l:ls) = + let matchfn t = l `elem` tgSemantics t+ (match, cands2) = partition matchfn cands+ next = buildColumns cands2 ls+ in Map.insert l match next++-- ----------------------------------------------------------------------+-- Initial Automaton+-- ----------------------------------------------------------------------++buildSeedAut :: SemMap -> Sem -> PolAut+buildSeedAut cands tsem = + let start = polstart []+ hasZero (x,y) = x <= 0 && y >= 0+ isFinal (PolSt c _ pols) = + c == length tsem && all hasZero pols+ initAut = NFA + { startSt = start+ , isFinalSt = Just isFinal+ , finalStList = []+ , states = [[start]]+ , transitions = Map.empty }+ in nubAut $ buildSeedAut' cands tsem 1 initAut++-- for each literal...+buildSeedAut' :: SemMap -> Sem -> Int -> PolAut -> PolAut +buildSeedAut' _ [] _ aut = aut +buildSeedAut' cands (l:ls) i aut = + let -- previously created candidates + prev = head $ states aut+ -- candidates that match the target semantics+ tcands = Map.findWithDefault [] l cands+ -- create the next batch of states+ fn st ap = buildSeedAutHelper tcands l i st ap+ (newAut,newStates) = foldr fn (aut,[]) prev+ next = nub newStates : states aut+ -- recursive step to the next literal+ in buildSeedAut' cands ls (i+1) (newAut { states = next })++-- for each candidate corresponding to literal l...+buildSeedAutHelper :: [TagElem]+ -> Literal GeniVal+ -> Int+ -> PolState+ -> (PolAut,[PolState])+ -> (PolAut,[PolState])+buildSeedAutHelper cs l i st (aut,prev) =+ let -- get the extra semantics from the last state+ (PolSt _ ex1 _) = st+ -- candidates that match the target semantics and which+ -- do not overlap the extra baggage semantics+ tcand = [ Just t | t <- cs+ , isEmptyIntersect ex1 (tsemantics t) ]+ -- add the transitions out of the current state + addT tr (a,n) = (addTrans a st tr st2, st2:n)+ where + st2 = PolSt i (delete l $ ex1 ++ ex2) []+ ex2 = case tr of + Nothing -> [] + Just tr_ -> tsemantics tr_+ in if (l `elem` ex1) + then addT Nothing (aut,prev)+ else foldr addT (aut,prev) tcand ++-- ----------------------------------------------------------------------+-- Construction+-- ----------------------------------------------------------------------++buildPolAut :: PolarityKey -> Interval -> PolAut -> PolAut+buildPolAut k initK skelAut =+ let concatPol p (PolSt pr b pol) = PolSt pr b (p:pol)+ newStart = concatPol initK $ startSt skelAut+ --+ initAut = skelAut + { startSt = newStart+ , states = [[newStart]]+ , transitions = Map.empty }+ -- cand' = observe "candidate map" cand + in nubAut $ buildPolAut' k (transitions skelAut) initAut ++{-+Our helper function looks at a single state in the skeleton automaton+and at one of the states in the new automaton which correspond to it.+We use the transitions from the old automaton to determine which states+to construct. Note: there can be more than one state in the automaton+which corresponds to a state in the old automaton. This is because we+are looking at a different polarity key, so that whereas two candidates+automaton may transition to the same state in the old automaton, their+polarity effects for the new key will make them diverge in the new+automaton. +-}++buildPolAut' :: PolarityKey -> PolTransFn -> PolAut -> PolAut+-- for each literal... (this is implicit in the automaton state grouping)+buildPolAut' fk skeleton aut = + let -- previously created candidates + prev = head $ states aut + -- create the next batch of states+ fn st ap = buildPolAutHelper fk skeleton st ap+ (newAut,newStates) = foldr fn (aut,Set.empty) prev+ next = Set.toList newStates : states aut+ -- recursive step to the next literal+ in if Set.null newStates+ then aut+ else buildPolAut' fk skeleton (newAut { states = next })++-- given a previously created state...+buildPolAutHelper :: PolarityKey -> PolTransFn -> PolState -> (PolAut,Set.Set PolState) -> (PolAut,Set.Set PolState)+buildPolAutHelper fk skeleton st (aut,prev) =+ let -- reconstruct the skeleton state used to build st + PolSt pr ex (po1:skelpo1) = st+ skelSt = PolSt pr ex skelpo1+ -- for each transition out of the current state+ -- nb: a transition is (next state, [labels to that state])+ trans = Map.toList $ Map.findWithDefault Map.empty skelSt skeleton+ result = foldr addT (aut,prev) trans+ -- . for each label to the next state st2+ addT (oldSt2,trs) (a,n) = foldr (addTS oldSt2) (a,n) trs+ -- .. calculate a new state and add a transition to it+ addTS skel2 tr (a,n) = (addTrans a st tr st2, Set.insert st2 n)+ where st2 = newSt tr skel2+ --+ newSt :: Maybe TagElem -> PolState -> PolState+ newSt t skel2 = PolSt pr2 ex2 (po2:skelPo2)+ where + PolSt pr2 ex2 skelPo2 = skel2 + po2 = po1 !+! Map.findWithDefault (ival 0) fk pol+ pol = case t of Nothing -> Map.empty + Just t2 -> tpolarities t2+ in result ++-- ----------------------------------------------------------------------+-- Pruning+-- ----------------------------------------------------------------------++{-|+The pruning algorithm takes as arguments a list of states to process.+Among these, any state which does not have outgoing transitions is+placed on the blacklist. We remove all transitions to the blacklist and+all states that only transition to the blacklist, and then we repeat+pruning, with a next batch of states.++Finally, we return the pruned automaton. Note: in order for this to+work, it is essential that the final states are *not* included in the+list of states to process.+-}+prune :: PolAut -> PolAut+prune aut = + let theStates = states aut+ final = finalSt aut+ -- (remember that states is a list of lists) + lastStates = head theStates + nextStates = tail theStates + nonFinal = (lastStates \\ final)+ -- the helper function will rebuild the state list+ firstAut = aut { states = [] }+ pruned = prune' (nonFinal:nextStates) firstAut + -- re-add the final state!+ statesPruned = states pruned+ headPruned = head statesPruned+ tailPruned = tail statesPruned+ in if (null theStates) + then aut+ else pruned { states = (headPruned ++ final) : tailPruned } ++prune' :: [[PolState]] -> PolAut -> PolAut+prune' [] oldAut = oldAut { states = reverse $ states oldAut }+prune' (sts:next) oldAut = + let -- calculate the blacklist+ oldT = transitions oldAut+ oldSt = states oldAut+ transFrom st = Map.lookup st oldT+ blacklist = filter (isNothing.transFrom) sts+ -- given a st: filter out all transitions to the blacklist+ allTrans = Map.toList $ transitions oldAut+ -- delete all transitions to the blacklist+ miniTrim = Map.filterWithKey (\k _ -> not (k `elem` blacklist))+ -- extra cleanup: delete from map states that only transition to the blacklist+ trim = Map.filterWithKey (\k m -> not (k `elem` blacklist || Map.null m))+ -- execute the kill and miniKill filters+ newT = trim $ Map.fromList [ (st2, miniTrim m) | (st2,m) <- allTrans ]+ -- new list of states and new automaton+ newSts = sts \\ blacklist+ newAut = oldAut { transitions = newT,+ states = newSts : oldSt }+ {- + -- debugging code+ debugstr = "blacklist: [\n" ++ debugstr' ++ "]"+ debugstr' = concat $ intersperse "\n" $ map showSt blacklist+ showSt (PolSt pr ex po) = showPr pr ++ showEx ex ++ showPo po+ showPr (_,pr,_) = pr ++ " " + showPo po = concat $ intersperse "," $ map show po+ showEx ex = if (null ex) then "" else (showSem ex)+ -}+ -- recursive step+ in if null blacklist+ then oldAut { states = (reverse oldSt) ++ (sts:next) }+ else prune' next newAut ++-- ====================================================================+-- Zero-literal semantics+-- ====================================================================++type PredLite = (String,[GeniVal]) -- handle is head of arg list +type SemWeightMap = Map.Map PredLite SemPols++-- | Returns a modified input semantics and lexical selection in which pronouns+-- are properly accounted for.+fixPronouns :: (Sem,[TagElem]) -> (Sem,[TagElem])+fixPronouns (tsem,cands) = + let -- part 1 (for each literal get smallest charge for each idx)+ getpols :: TagElem -> [ (PredLite,SemPols) ]+ getpols x = zip [ (prettyStr p, h:as) | Literal h p as <- tsemantics x ] (tsempols x)+ sempols :: [ (PredLite,SemPols) ]+ sempols = concatMap getpols cands+ usagemap :: SemWeightMap + usagemap = Map.fromListWith (zipWith min) sempols+ -- part 2 (cancel sem polarities)+ chargemap :: Map.Map GeniVal Int -- index to charge + chargemap = Map.fromListWith (+) $ concatMap clump $ Map.toList usagemap+ where clump ((_,is),ps) = zip is ps+ -- part 3 (adding extra semantics)+ indices = concatMap fn (Map.toList chargemap) + where fn (i,c) = replicate (negate c) i+ -- the extra columns + extraSem = map indexLiteral indices+ tsem2 = sortSem (tsem ++ extraSem)+ -- zero-literal semantic items to realise the extra columns + zlit = filter (null.tsemantics) cands+ cands2 = (cands \\ zlit) ++ concatMap fn indices+ where fn i = map (tweak i) zlit+ tweak i x = assignIndex i $ x { tsemantics = [indexLiteral i] }+ -- part 4 (insert excess pronouns in tree sem)+ comparefn :: GeniVal -> Int -> Int -> [GeniVal]+ comparefn i ct cm = if cm < ct then extra else []+ where maxNeeded = Map.findWithDefault 0 i chargemap -- cap the number added+ extra = replicate (min (negate maxNeeded) (ct - cm)) i+ comparePron :: (PredLite,SemPols) -> [GeniVal]+ comparePron (lit,c1) = concat $ zipWith3 comparefn idxs c1 c2+ where idxs = snd lit+ c2 = Map.findWithDefault [] lit usagemap+ addextra :: TagElem -> TagElem+ addextra c = c { tsemantics = sortSem (sem ++ extra) }+ where sem = tsemantics c+ extra = map indexLiteral $ concatMap comparePron (getpols c)+ cands3 = map addextra cands2+ in (tsem2, cands3)++-- | Builds a fake semantic predicate that the index counting mechanism uses to+-- represent extra columns.+indexLiteral :: GeniVal -> Literal GeniVal+indexLiteral x = Literal x mkGAnon []++-- Returns True if the given literal was introduced by the index counting mechanism+isExtraCol :: Literal GeniVal -> Bool+isExtraCol (Literal _ p []) = isAnon p+isExtraCol _ = False++-- | 'assignIndex' is a useful way to restrict the behaviour of+-- null semantic items like pronouns using the information generated by+-- the index counting mechanism. The problem with null semantic items +-- is that their indices are not set, which means that they could+-- potentially combine with any other tree. To make things more +-- efficient, we can set the index of these items and thus reduce the+-- number of spurious combinations. +-- +-- Notes+--+-- * These combinations could produce false results if the+-- input has to use multiple pronouns. For example, if you wanted to say+-- something like “John promises Mary to convince Paul to give her+-- his book”, these combinations could instead produce “give him+-- *her* book“.+--+-- * This function works by FS unification on the root node of the+-- tree with the *[idx:i]*. If unification is not possible, +-- we simply return the tree as is.+--+-- * This function renames the tree by appending the index to its name+assignIndex :: GeniVal -> TagElem -> TagElem +assignIndex i te =+ let idxfs = [ AvPair __idx__ i ]+ oldt = ttree te+ oldr = root oldt+ tfup = gup oldr+ --+ in case unifyFeat tfup idxfs of+ Nothing -> te+ Just (gup2, sub) -> replace sub $ te { ttree = newt }+ where newt = rootUpd oldt $ oldr { gup = gup2 }++-- ====================================================================+-- Further optimisations+-- ====================================================================++-- Index constraints +-- -----------------+detectIdxConstraints :: Flist GeniVal -> Flist GeniVal -> PolMap+detectIdxConstraints cs interface =+ let matches = intersect cs interface+ matchStr = map idxConstraintKey matches+ in Map.fromList $ zip matchStr ((repeat.ival) 1)++declareIdxConstraints :: Flist GeniVal -> PolMap+declareIdxConstraints = Map.fromList . (map declare) where+ declare c = (idxConstraintKey c, minusone)+ minusone = ival (-1)++-- TODO: test that index constraints come first+idxConstraintKey :: AvPair GeniVal -> PolarityKey+idxConstraintKey = PolarityKeyStr . ("." <>) . pretty++-- Automatic polarity detection+-- ----------------------------+suggestPolFeatures :: [TagElem] -> [Text]+suggestPolFeatures tes =+ let -- only initial trees need be counted; in aux trees, the+ -- root node is implicitly canceled by the foot node+ rfeats, sfeats :: [Flist GeniVal]+ rfeats = map (gdown.root.ttree) $ filter (\t -> ttype t == Initial) tes+ sfeats = [ concat s | s <- map substTops tes, (not.null) s ]+ --+ attrs :: Flist GeniVal -> [Text]+ attrs avs = [ a | AvPair a v <- avs, isJust (gConstraints v) ]+ theAttributes = map attrs $ rfeats ++ sfeats+ in if null theAttributes then [] else foldr1 intersect theAttributes++-- FIXME: temporary HACKY code - delete me as soon as possible (written+-- 2006-03-30+--+-- only initial trees need be counted; in aux trees, the+-- root node is implicitly canceled by the foot node+detectSansIdx :: [TagElem] -> [TagElem]+detectSansIdx =+ let rfeats t = (gdown.root.ttree) t+ feats t | ttype t == Initial = concat $ rfeats t : substTops t+ feats t = concat $ substTops t+ attrs avs = [ a | AvPair a v <- avs, isJust (gConstraints v) ]+ hasIdx t = __idx__ `elem` (attrs.feats $ t) || (ttype t /= Initial && (null $ substTops t))+ in filter (not.hasIdx)++detectPols :: Set.Set PolarityAttr -> TagElem -> TagElem+detectPols attrs t =+ t { tpolarities = addPols (detectPolsH attrs t) (tpolarities t) }++-- Chart sharing+-- -------------++-- | Given a list of paths (i.e. a list of list of trees)+-- return a list of trees such that each tree is annotated with the paths it+-- belongs to.+detectPolPaths :: [[TagElem]] -> [(TagElem,BitVector)]+detectPolPaths paths = + let pathFM = detectPolPaths' Map.empty 0 paths+ lookupTr k = Map.findWithDefault 0 k pathFM+ in map (\k -> (k, lookupTr k)) $ Map.keys pathFM++type PolPathMap = Map.Map TagElem BitVector+detectPolPaths' :: PolPathMap -> Int -> [[TagElem]] -> PolPathMap ++detectPolPaths' accFM _ [] = accFM+detectPolPaths' accFM counter (path:ps) = + let currentBits = shiftL 1 counter -- shift counter times the 1 bit+ fn f [] = f+ fn f (t:ts) = fn (Map.insertWith (.|.) t currentBits f) ts + newFM = fn accFM path+ in detectPolPaths' newFM (counter+1) ps++-- | Render the list of polarity automaton paths as a string+prettyPolPaths :: BitVector -> Text+prettyPolPaths paths =+ T.intercalate ", " $ map pretty pathlist+ where+ pathlist = prettyPolPaths' paths 1++prettyPolPaths' :: BitVector -> Int -> [Int] +prettyPolPaths' 0 _ = []+prettyPolPaths' bv counter = + if b then (counter:next) else next+ where b = testBit bv 0+ next = prettyPolPaths' (shiftR bv 1) (counter + 1)++-- Semantic sorting+-- ----------------++sortSemByFreq :: Sem -> [TagElem] -> Sem+sortSemByFreq tsem cands = + let counts = map lenfn tsem + lenfn l = length $ filter fn cands + where fn x = l `elem` (tsemantics x)+ -- note: we introduce an extra hack to push+ -- index-counted extra columns to the end; just for UI reasons+ sortfn a b + | isX a && isX b = compare (snd a) (snd b)+ | isX a = GT+ | isX b = LT+ | otherwise = compare (snd a) (snd b)+ where isX = isExtraCol.fst + sorted = sortBy sortfn $ zip tsem counts + in (fst.unzip) sorted ++-- ----------------------------------------------------------------------+-- Types+-- ----------------------------------------------------------------------++-- Polarity NFA++data PolState = PolSt Int [Literal GeniVal] [(Int,Int)]+ -- ^ position in the input semantics, extra semantics, + -- polarity interval+ deriving (Eq)+type PolTrans = TagElem+type PolAut = NFA PolState PolTrans+type PolTransFn = Map.Map PolState (Map.Map PolState [Maybe PolTrans])++instance Show PolState+ where show (PolSt pr ex po) = show pr ++ " " ++ prettyStr ex ++ show po+-- showPred pr ++ " " ++ showSem ex ++ show po++instance Ord PolState where+ compare (PolSt pr1 ex1 po1) (PolSt pr2 ex2 po2) = + let prC = compare pr1 pr2+ expoC = compare (ex1,po1) (ex2,po2)+ in if (prC == EQ) then expoC else prC++-- We include also some fake states which are useful for general+-- housekeeping during the main algortihms.+fakestate :: Int -> [Interval] -> PolState+fakestate s pol = PolSt s [] pol --PolSt (0, s, [""]) [] pol++-- | an initial state for polarity automata+polstart :: [Interval] -> PolState+polstart pol = fakestate 0 pol -- fakestate "START" pol
− src/NLP/GenI/Polarity.lhs
@@ -1,1206 +0,0 @@-% GenI surface realiser-% Copyright (C) 2009 Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.--\chapter{Polarity Optimisation}-\label{cha:Polarity}--We introduce a notion of polarities as a means of pre-detecting-incompatibilities between candidate trees for different propositions.-This optimisation is inserted between candidate selection -(section \ref{sec:candidate_selection})-and chart generation. The input to this optimisation is the-\jargon{target semantics} and the corresponding \jargon{candidate- trees}.--This whole optimisation is based on adding polarities to the grammar.-We have a set of strings which we call \jargon{polarity keys}, and some-positive or negative integers which we call \jargon{charges}. Each tree-in the grammar may assign a charge to some number of polarity keys. For-example, here is a simple grammar that uses the polarity keys n and v.--\begin{tabular}{|l|l|}-\hline-tree & polarity effects \\-\hline-s(n$\downarrow$, v$\downarrow$, n$\downarrow$) & -2n -v\\-v(hates) & +v\\-n(mary) & +n\\-n(john) & +n\\-\hline-\end{tabular}--For now, these annotations are done by hand, and are based on syntactic-criteria (substitution and root node categories) but one could envisage-alternate criteria or an eventual means of automating the process. --The basic idea is to use the polarity keys to determine which subsets of-candidate trees are incompatible with each other and rule them out. We-construct a finite state automaton which uses polarity keys to-pre-calculate the compatibility of sets of trees. At the end of the-optimisation, we are left with an automaton, each path of which is a-potentially compatible set of trees. We then preform surface-realisation seperately, treating each path as a set of candidate trees.--\emph{Important note}: one thing that may be confusing in this chapter-is that we refer to polarities (charges) as single integers, e.g, $-2n$.-In reality, to account for weird stuff like atomic disjunction, we do-not use simple integers, but polarities intervals, so more something -like $(-2,-2)n$! But for the most part, the intervals are zero length,-and you can just think of $-2n$ as shorthand for $(-2,-2)n$.--\begin{code}-module NLP.GenI.Polarity(- -- * Entry point- PolAut, PolState(PolSt), AutDebug, PolResult,- buildAutomaton,-- -- * Inner stuff (exported for debugging?)- makePolAut,- fixPronouns,- detectSansIdx, detectPolFeatures, detectPols, detectPolPaths,- declareIdxConstraints, detectIdxConstraints,- showLite, showLitePm, showPolPaths, showPolPaths',-- -- re-exported from Automaton- automatonPaths, finalSt,- NFA(states, transitions),- )-where-\end{code}--\begin{code}-import Data.Bits-import qualified Data.Set as Set-import qualified Data.Map as Map-import Data.List-import Data.Maybe (isNothing, isJust)-import Data.Tree (flatten)-import qualified Data.Set as Set--import NLP.GenI.Automaton-import NLP.GenI.Btypes(Pred, SemInput, Sem, Flist, AvPair(..), showAv,- GeniVal(..), fromGConst, isConst,- replace,- emptyPred, Ptype(Initial), - showFlist, showSem, sortSem,- GNode, root, gup, gdown, gtype, GType(Subs),- SemPols, unify, unifyFeat, rootUpd)-import NLP.GenI.General(- BitVector, isEmptyIntersect, thd3,- Interval, ival, (!+!), showInterval)-import NLP.GenI.PolarityTypes-import NLP.GenI.Tags(TagElem(..), TagItem(..), setTidnums)-\end{code}--\section{Interface}--\begin{code}--- | intermediate auts, seed aut, final aut, potentially modified sem-type PolResult = ([AutDebug], PolAut, PolAut, Sem)-type AutDebug = (PolarityKey, PolAut, PolAut)---- | Constructs a polarity automaton. For debugging purposes, it returns--- all the intermediate automata produced by the construction algorithm.-buildAutomaton :: Set.Set PolarityAttr -- ^ polarities to detect- -> Flist -- ^ root features to compensate for- -> PolMap -- ^ explicit extra polarities- -> SemInput -- ^ input semantics- -> [TagElem] -- ^ lexical selection- -> PolResult-buildAutomaton polarityAttrs rootFeat extrapol (tsem,tres,_) candRaw =- let -- root categories, index constraints, and external polarities- rcatPol :: Map.Map PolarityKey Interval- rcatPol = Map.fromList . pdJusts- $ map (\v -> detectPolarityForAttr (-1) (pAttr v) rootFeat)- $ Set.toList polarityAttrs- pAttr p@(SimplePolarityAttr _) = spkAtt p- pAttr p@(RestrictedPolarityAttr _ _) = rpkAtt p- --- allExtraPols = Map.unionsWith (!+!) [ extrapol, inputRest, rcatPol ]- -- index constraints on candidate trees- detect = detectIdxConstraints tres- constrain t = t { tpolarities = Map.unionWith (!+!) p r- } --, tinterface = [] }- where p = tpolarities t- r = detect . tinterface $ t- candRest = map constrain candRaw- inputRest = declareIdxConstraints tres- -- polarity detection - cand = detectPols polarityAttrs candRest- -- building the automaton- in makePolAut cand tsem allExtraPols-\end{code}--\section{The automaton itself - outline}-\label{polarity:overview}--We start with the controller function (the general architecture) and-detail the individual steps in the following sections. The basic-architecture is as follows:--\begin{enumerate}-\item Build a seed automaton (section \ref{sec:seed_automaton}).-\item For each polarity key, elaborate the - automaton with the polarity information for that key- (section \ref{sec:automaton_construction}) and minimise- the automaton (section \ref{sec:automaton_pruning}).-\end{enumerate}--The above process can be thought of as a more efficient way of-constructing an automaton for each polarity key, minimising said-automaton, and then taking their intersection. In any case, -we return everything a tuple with (1) a list of the automota that-were created (2) the final automaton (3) a possibly modified-input semantics. The first item is only neccesary for debugging; only-the last two are important.--Note: -\begin{itemize}-\item the \fnparam{extraPol} argument is a map containing any initial- values for polarity keys. This is useful to impose external filters- like ``I only want expressions where the object is topicalised''. -\item to recuperate something useful from these automaton, it might- be helpful to call \fnref{automatonPaths} on it.-\end{itemize}--\begin{code}-makePolAut :: [TagElem] -> Sem -> PolMap -> PolResult-makePolAut candsRaw tsemRaw extraPol =- let -- polarity items- ksCands = concatMap (Map.keys . tpolarities) cands- ksExtra = Map.keys extraPol- ks = sortBy (flip compare) $ nub $ ksCands ++ ksExtra- -- perform index counting- (tsem, cands') = fixPronouns (tsemRaw,candsRaw)- cands = setTidnums cands'- -- sorted semantics (for more efficient construction)- sortedsem = sortSemByFreq tsem cands - -- the seed automaton- smap = buildColumns cands sortedsem - seed = buildSeedAut smap sortedsem- -- building and remembering the automata - build k xs = (k,aut,prune aut):xs- where aut = buildPolAut k initK (thd3 $ head xs)- initK = Map.findWithDefault (ival 0) k extraPol- res = foldr build [(PolarityKey "(seed)",seed,prune seed)] ks- in (reverse res, seed, thd3 $ head res, tsem)-\end{code}--% ====================================================================-\section{Polarity automaton}-\label{sec:polarity_automaton}-% ====================================================================--We construct a finite state automaton for each polarity key that is in-the set of trees. It helps to imagine a table where each column-corresponds to a single proposition. --\begin{center}-\begin{tabular}{|c|c|c|}-\hline-\semexpr{gift(g)} & \semexpr{cost(g,x)} & \semexpr{high(x)} \\-\hline-\natlang{the gift} \color{blue}{+1np} & -\natlang{the cost of} & -\natlang{is high} \color{red}{-1np} \\-%-\natlang{the present} \color{blue}{+1np} & -\natlang{costs} \color{red}{-1np} & -\natlang{a lot} \\-%-&& \natlang{much} \\-\hline-\end{tabular}-\end{center}--Each column (proposition) has a different number of cells which-corresponds to the lexical ambiguity for that proposition, more-concretely, the number of candidate trees for that proposition. The-\jargon{polarity automaton} describes the different ways we can traverse-the table from column to column, choosing a cell to pass through at each-step and accumulating polarity along the way. Each state represents the-polarity at a column and each transition represents the tree we chose to-get there. All transitions from one columns $i$ to the next $i+1$ that-lead to the same accumulated polarity lead to the same state. --% -----------------------------------------------------------------------\subsection{Columns}-% ------------------------------------------------------------------------We build the columns for the polarity automaton as follows. Given a-input semantics \texttt{sem} and a list of trees \texttt{cands}, we-group the trees by the first literal of sem that is part of their tree-semantics. --Note: this is not the same function as Tags.mapBySem! The fact that we-preserve the order of the input semantics is important for our handling-of multi-literal semantics and for semantic frequency sorting.--\begin{code}-buildColumns :: (TagItem t) => [t] -> Sem -> Map.Map Pred [t] -buildColumns cands [] = - Map.singleton emptyPred e - where e = filter (null.tgSemantics) cands--buildColumns cands (l:ls) = - let matchfn t = l `elem` tgSemantics t- (match, cands2) = partition matchfn cands- next = buildColumns cands2 ls- in Map.insert l match next-\end{code}--% -----------------------------------------------------------------------\subsection{Initial Automaton}-\label{sec:seed_automaton}-% ------------------------------------------------------------------------We first construct a relatively trivial polarity automaton without any-polarity effects. Each state except the start state corresponds-to a literal in the target semantics, and the transitions to a state -consist of the trees whose semantics is subsumed by that literal. --\begin{code}-buildSeedAut :: SemMap -> Sem -> PolAut-buildSeedAut cands tsem = - let start = polstart []- hasZero (x,y) = x <= 0 && y >= 0- isFinal (PolSt c _ pols) = - c == length tsem && all hasZero pols- initAut = NFA - { startSt = start- , isFinalSt = Just isFinal- , finalStList = []- , states = [[start]]- , transitions = Map.empty }- in nubAut $ buildSeedAut' cands tsem 1 initAut---- for each literal...-buildSeedAut' :: SemMap -> Sem -> Int -> PolAut -> PolAut -buildSeedAut' _ [] _ aut = aut -buildSeedAut' cands (l:ls) i aut = - let -- previously created candidates - prev = head $ states aut- -- candidates that match the target semantics- tcands = Map.findWithDefault [] l cands- -- create the next batch of states- fn st ap = buildSeedAutHelper tcands l i st ap- (newAut,newStates) = foldr fn (aut,[]) prev- next = nub newStates : states aut- -- recursive step to the next literal- in buildSeedAut' cands ls (i+1) (newAut { states = next })---- for each candidate corresponding to literal l...-buildSeedAutHelper :: [TagElem] -> Pred -> Int -> PolState -> (PolAut,[PolState]) -> (PolAut,[PolState])-buildSeedAutHelper cs l i st (aut,prev) =- let -- get the extra semantics from the last state- (PolSt _ ex1 _) = st- -- candidates that match the target semantics and which- -- do not overlap the extra baggage semantics- tcand = [ Just t | t <- cs- , isEmptyIntersect ex1 (tsemantics t) ]- -- add the transitions out of the current state - addT tr (a,n) = (addTrans a st tr st2, st2:n)- where - st2 = PolSt i (delete l $ ex1 ++ ex2) []- ex2 = case tr of - Nothing -> [] - Just tr_ -> tsemantics tr_- in if (l `elem` ex1) - then addT Nothing (aut,prev)- else foldr addT (aut,prev) tcand -\end{code}--% -----------------------------------------------------------------------\subsection{Construction}-\label{sec:automaton_construction}-\label{sec:automaton_intersection}-% ------------------------------------------------------------------------The goal is to construct a polarity automaton which accounts for a-given polarity key $k$. The basic idea is that given -literals $p_1..p_n$ in the target semantics, we create a start state,-calculate the states/transitions to $p_1$ and succesively calculate-the states/transitions from proposition $p_x$ to $p_{x+1}$ for all-$1 < x < n$. --The ultimate goal is to construct an automaton that accounts for -multiple polarity keys. The simplest approach would be to -calculate a seperate automaton for each key, prune them all and -then intersect the pruned automaton together, but we can do much -better than that. Since the pruned automata are generally much-smaller in size, we perform an iterative intersection by using -a previously pruned automaton as the skeleton for the current -automaton. This is why we don't pass any literals or candidates-to the construction step; it takes them directly from the previous-automaton. See also section \ref{sec:seed_automaton} for the seed -automaton that you can use when there is no ``previous automaton''.--\begin{code}-buildPolAut :: PolarityKey -> Interval -> PolAut -> PolAut-buildPolAut k initK skelAut =- let concatPol p (PolSt pr b pol) = PolSt pr b (p:pol)- newStart = concatPol initK $ startSt skelAut- --- initAut = skelAut - { startSt = newStart- , states = [[newStart]]- , transitions = Map.empty }- -- cand' = observe "candidate map" cand - in nubAut $ buildPolAut' k (transitions skelAut) initAut -\end{code}--Our helper function looks at a single state in the skeleton automaton-and at one of the states in the new automaton which correspond to it.-We use the transitions from the old automaton to determine which states-to construct. Note: there can be more than one state in the automaton-which corresponds to a state in the old automaton. This is because we-are looking at a different polarity key, so that whereas two candidates-automaton may transition to the same state in the old automaton, their-polarity effects for the new key will make them diverge in the new-automaton. --\begin{code}-buildPolAut' :: PolarityKey -> PolTransFn -> PolAut -> PolAut--- for each literal... (this is implicit in the automaton state grouping)-buildPolAut' fk skeleton aut = - let -- previously created candidates - prev = head $ states aut - -- create the next batch of states- fn st ap = buildPolAutHelper fk skeleton st ap- (newAut,newStates) = foldr fn (aut,Set.empty) prev- next = Set.toList newStates : states aut- -- recursive step to the next literal- in if Set.null newStates- then aut- else buildPolAut' fk skeleton (newAut { states = next })---- given a previously created state...-buildPolAutHelper :: PolarityKey -> PolTransFn -> PolState -> (PolAut,Set.Set PolState) -> (PolAut,Set.Set PolState)-buildPolAutHelper fk skeleton st (aut,prev) =- let -- reconstruct the skeleton state used to build st - PolSt pr ex (po1:skelpo1) = st- skelSt = PolSt pr ex skelpo1- -- for each transition out of the current state- -- nb: a transition is (next state, [labels to that state])- trans = Map.toList $ Map.findWithDefault Map.empty skelSt skeleton- result = foldr addT (aut,prev) trans- -- . for each label to the next state st2- addT (oldSt2,trs) (a,n) = foldr (addTS oldSt2) (a,n) trs- -- .. calculate a new state and add a transition to it- addTS skel2 tr (a,n) = (addTrans a st tr st2, Set.insert st2 n)- where st2 = newSt tr skel2- --- newSt :: Maybe TagElem -> PolState -> PolState- newSt t skel2 = PolSt pr2 ex2 (po2:skelPo2)- where - PolSt pr2 ex2 skelPo2 = skel2 - po2 = po1 !+! Map.findWithDefault (ival 0) fk pol- pol = case t of Nothing -> Map.empty - Just t2 -> tpolarities t2- in result -\end{code}--% -----------------------------------------------------------------------\subsection{Pruning}-\label{sec:automaton_pruning}-% ------------------------------------------------------------------------Any path through the automaton which does not lead to final-polarity of zero sum can now be eliminated. We do this by stepping-recursively backwards from the final states: --\begin{code}-prune :: PolAut -> PolAut-prune aut = - let theStates = states aut- final = finalSt aut- -- (remember that states is a list of lists) - lastStates = head theStates - nextStates = tail theStates - nonFinal = (lastStates \\ final)- -- the helper function will rebuild the state list- firstAut = aut { states = [] }- pruned = prune' (nonFinal:nextStates) firstAut - -- re-add the final state!- statesPruned = states pruned- headPruned = head statesPruned- tailPruned = tail statesPruned- in if (null theStates) - then aut- else pruned { states = (headPruned ++ final) : tailPruned } -\end{code}--The pruning algorithm takes as arguments a list of states to process.-Among these, any state which does not have outgoing transitions is-placed on the blacklist. We remove all transitions to the blacklist and-all states that only transition to the blacklist, and then we repeat-pruning, with a next batch of states. --Finally, we return the pruned automaton. Note: in order for this to-work, it is essential that the final states are *not* included in the-list of states to process.--\begin{code}-prune' :: [[PolState]] -> PolAut -> PolAut-prune' [] oldAut = oldAut { states = reverse $ states oldAut }-prune' (sts:next) oldAut = - let -- calculate the blacklist- oldT = transitions oldAut- oldSt = states oldAut- transFrom st = Map.lookup st oldT- blacklist = filter (isNothing.transFrom) sts- -- given a st: filter out all transitions to the blacklist- allTrans = Map.toList $ transitions oldAut- -- delete all transitions to the blacklist- miniTrim = Map.filterWithKey (\k _ -> not (k `elem` blacklist))- -- extra cleanup: delete from map states that only transition to the blacklist- trim = Map.filterWithKey (\k m -> not (k `elem` blacklist || Map.null m))- -- execute the kill and miniKill filters- newT = trim $ Map.fromList [ (st2, miniTrim m) | (st2,m) <- allTrans ]- -- new list of states and new automaton- newSts = sts \\ blacklist- newAut = oldAut { transitions = newT,- states = newSts : oldSt }- {- - -- debugging code- debugstr = "blacklist: [\n" ++ debugstr' ++ "]"- debugstr' = concat $ intersperse "\n" $ map showSt blacklist- showSt (PolSt pr ex po) = showPr pr ++ showEx ex ++ showPo po- showPr (_,pr,_) = pr ++ " " - showPo po = concat $ intersperse "," $ map show po- showEx ex = if (null ex) then "" else (showSem ex)- -}- -- recursive step- in if null blacklist- then oldAut { states = (reverse oldSt) ++ (sts:next) }- else prune' next newAut -\end{code}--% ====================================================================-\section{Zero-literal semantics}-\label{sec:multiuse}-\label{semantic_weights}-\label{sec:nullsem}-\label{sec:co-anchors}-% ====================================================================--Lexical items with a \jargon{null semantics} typically correspond to-functions words: complementisers \natlang{(John likes \textbf{to}-read.)}, subcategorised prepositions \natlang{(Mary accuses John-\textbf{of} cheating.)}. Such items need not be lexical items at all.-We can exploit TAG's support for trees with multiple anchors, by-treating them as co-anchors to some primary lexical item. The English-infinitival \natlang{to}, for example, can appear in the tree-\tautree{to~take} as \koweytree{s(comp(to),v(take),np$\downarrow$)}. --On the other hand, pronouns have a \jargon{zero-literal} semantics, one-which is not null, but which consists only of a variable index. For-example, the pronoun \natlang{she} in (\ref{ex:pronoun_pol_she}) has-semantics \semexpr{s} and in (\ref{ex:pronoun_pol_control}),-\natlang{he} has the semantics \semexpr{j}. --{\footnotesize-\eenumsentence{\label{ex:pronoun_pol} -\item \label{ex:pronoun_pol_sue} -\semexpr{joe(j), sue(s), book(b), lend(l,j,b,s), boring(b) } -\\ \natlang{Joe lends Sue a boring book.}--% Note for visually impaired readers: ignore anything with \color{white}. -% It is used as a form of indentation to help sighted users. -\item \label{ex:pronoun_pol_she} -\semexpr{joe(j), {\color{white}sue(s),} book(b), lend(l,j,b,s), boring(b) } -\\ \natlang{Joe lends her a boring book.}-}-\eenumsentence{\label{ex:pronoun_pol_control} -\item[{\color{white}a.}] \label{ex:pronoun_pol_control_inf}-\semexpr{joe(j), sue(s), leave(l,j), promise(p,j,s,l)}-\\ \natlang{Joe promises Sue to leave.}-\\ or \natlang{Joe promises Sue that he would leave.} -}}--In figure \ref{fig:polarity_automaton_zerolit_bad}, we compare the-construction of polarity automata for (\ref{ex:pronoun_pol_sue}, left)-and (\ref{ex:pronoun_pol_she}, right). Building an automaton for-(\ref{ex:pronoun_pol_she}) fails because \tautree{sue} is not available-to cancel the negative polarities for \tautree{lends}; instead, a-pronoun must be used to take its place. The problem is that the-selection of a lexical items is only triggered when the construction-algorithm visits one of its semantic literals. Since pronoun semantics-have zero literals, they are \emph{never} selected. Making pronouns-visible to the construction algorithm would require us to count the-indices from the input semantics. Each index refers to an entity. This-entity must be ``consumed'' by a syntactic functor (e.g. a verb) and-``provided'' by a syntactic argument (e.g. a noun).--%\footnote{This also holds true for sentences like \natlang{Joe sings-%badly and Sue sings well}, \semexpr{sing(s1,j) good(s1), sing(s2,m),-%bad(s2)} because each usage of \natlang{sings} actually corresponds to a-%different lexical item, \tautree{sings1} with the semantics-%\semexpr{sings(s1,j)} and \tautree{sings2} with \semexpr{sings(s2,m)}.}. --\begin{figure}[htpb]-\begin{center}-\includegraphics[scale=0.25]{images/zeroaut-noun.pdf}-\includegraphics[scale=0.25]{images/zeroaut-sans.pdf}-\end{center}-\vspace{-0.4cm}-\caption{Difficulty with zero-literal semantics.}-\label{fig:polarity_automaton_zerolit_bad}-\end{figure}--We make this explicit by annotating the semantics of the lexical input-(that is the set of lexical items selected on the basis of the input-semantics) with a form of polarities. Roughly, nouns provide-indices\footnote{except for predicative nouns, which like verbs, are-semantic functors} ($+$), modifiers leave them unaffected, and verbs-consume them ($-$). Predicting pronouns is then a matter of counting-the indices. If the positive and negative indices cancel each other-out, no pronouns are required. If there are more negative indices than-positive ones, then as many pronouns are required as there are negative-excess indices. In the table below, we show how the example semantics-above may be annotated and how many negative excess indices result:--\begin{center}-{\footnotesize-\begin{tabular}{|l|r|r|r|}-\hline-\multicolumn{1}{|c|}{\bf semantics} & -{\bf \tt b} &-{\bf \tt j} & -{\bf \tt s} \\ -\hline-\semexpr{joe(+j) sue(+s) book(+b) lend(l,-j,-b,-s) boring(b)} & -\semexpr{0} &-\semexpr{0} &-\semexpr{0} \\-\hline-\semexpr{joe(+j) {\color{white}sue(+s)} book(+b) lend(l,-j,-b,-s) boring(b)} & -\semexpr{0} &-\semexpr{0} &-\semexpr{1} \\-\hline-\semexpr{joe(+j) sue(+s) leave(l,-j,-s) promise(p,{\color{white}-}j,-s,l)} &-\semexpr{0} &-\semexpr{0} & -\semexpr{0} \\ -\hline-\semexpr{joe(+j) sue(+s) leave(l,-j,-s) promise(p,-j,-s,l)} &-\semexpr{0} &-\semexpr{1} & -\semexpr{0} \\ -\hline-\end{tabular}-}-\end{center}--Counting surplus indices allows us to establish the number of pronouns-used and thus gives us the information needed to build polarity-automata. We implement this by introducing a virtual literal for-negative excess index, and having that literal be realised by pronouns.-Building the polarity automaton as normal yields lexical combinations-with the required number of pronouns, as in figure-\ref{fig:polarity_automaton_zerolit}. --\begin{figure}[htpb]-\begin{center}-\includegraphics[scale=0.25]{images/zeroaut-pron.pdf}-\end{center}-\vspace{-0.4cm}-\caption{Constructing a polarity automaton with zero-literal semantics.}-\label{fig:polarity_automaton_zerolit}-\end{figure}--\label{different_sem_annotations}-The sitation is more complicated where the lexical input-contains lexical items with different annotations for the same-semantics. For instance, the control verb \natlang{promise} has two-forms: one which solicits an infinitive as in \natlang{promise to-leave}, and one which solicits a declarative clause as in-\natlang{promise that he would leave}. This means two different counts-of subject index \semexpr{j} in (\ref{ex:pronoun_pol_control}) : zero-for the form that subcategorises for the infinitive, or one for the-declarative. But to build a single automaton, these counts must be-reconciled, i.e., how many virtual literals do we introduce for-\semexpr{j}, zero or one? The answer is to introduce enough virtual-literals to satisfy the largest demand, and then use the multi-literal-extension to support alternate forms with a smaller demand. To handle-example (\ref{ex:pronoun_pol_control}), we introduce one virtual literal-for \semexpr{j} so that the declarative form can be produced, and treat-the soliciting \natlang{promise} as though its semantics includes that-literal along with its regular semantics (figure-\ref{fig:polarity_automaton_zerolit_promise}). In other words, the-infinitive-soliciting form is treated as if it already fulfils the role-of a pronoun, and does not need one in its lexical combination.--\begin{figure}[htpb]-\begin{center}-\includegraphics[scale=0.25]{images/zeroaut-promise.pdf}-\end{center}-\vspace{-0.4cm}-\caption{Constructing a polarity automaton with zero-literal semantics.}-\label{fig:polarity_automaton_zerolit_promise}-\end{figure}--We insert pronouns into the input semantics using the following process:-\begin{enumerate}-\item For each literal in the input semantics, establish the- smallest charge for each of its semantic indices.-\item Cancel out the polarities for every index in the input- semantics.-\item Compensate for any uncancelled negative polarities by an- adding an additional literal to the input semantics -- a pronoun --- for every negative charge.-\item Finally, deal with the problem of lexical items who require fewer- pronouns than predicted by inserting the excess pronouns in their extra- literal semantics (see page \pageref{different_sem_annotations})-\end{enumerate}--\begin{code}-type PredLite = (String,[GeniVal]) -- handle is head of arg list -type SemWeightMap = Map.Map PredLite SemPols---- | Returns a modified input semantics and lexical selection in which pronouns--- are properly accounted for.-fixPronouns :: (Sem,[TagElem]) -> (Sem,[TagElem])-fixPronouns (tsem,cands) = - let -- part 1 (for each literal get smallest charge for each idx)- getpols :: TagElem -> [ (PredLite,SemPols) ]- getpols x = zip [ (show p, h:as) | (h,p,as) <- tsemantics x ] (tsempols x)- sempols :: [ (PredLite,SemPols) ]- sempols = concatMap getpols cands- usagemap :: SemWeightMap - usagemap = Map.fromListWith (zipWith min) sempols- -- part 2 (cancel sem polarities)- chargemap :: Map.Map GeniVal Int -- index to charge - chargemap = Map.fromListWith (+) $ concatMap clump $ Map.toList usagemap- where clump ((_,is),ps) = zip is ps- -- part 3 (adding extra semantics)- indices = concatMap fn (Map.toList chargemap) - where fn (i,c) = replicate (negate c) i- -- the extra columns - extraSem = map indexPred indices- tsem2 = sortSem (tsem ++ extraSem)- -- zero-literal semantic items to realise the extra columns - zlit = filter (null.tsemantics) cands- cands2 = (cands \\ zlit) ++ concatMap fn indices- where fn i = map (tweak i) zlit- tweak i x = assignIndex i $ x { tsemantics = [indexPred i] }- -- part 4 (insert excess pronouns in tree sem)- comparefn :: GeniVal -> Int -> Int -> [GeniVal]- comparefn i ct cm = if cm < ct then extra else []- where maxNeeded = Map.findWithDefault 0 i chargemap -- cap the number added- extra = replicate (min (negate maxNeeded) (ct - cm)) i- comparePron :: (PredLite,SemPols) -> [GeniVal]- comparePron (lit,c1) = concat $ zipWith3 comparefn idxs c1 c2- where idxs = snd lit- c2 = Map.findWithDefault [] lit usagemap- addextra :: TagElem -> TagElem- addextra c = c { tsemantics = sortSem (sem ++ extra) }- where sem = tsemantics c- extra = map indexPred $ concatMap comparePron (getpols c)- cands3 = map addextra cands2- in (tsem2, cands3)---- | Builds a fake semantic predicate that the index counting mechanism uses to--- represent extra columns.-indexPred :: GeniVal -> Pred-indexPred x = (x, GAnon, [])---- Returns True if the given literal was introduced by the index counting mechanism-isExtraCol :: Pred -> Bool-isExtraCol (_,GAnon,[]) = True-isExtraCol _ = False-\end{code}--\paragraph{assignIndex} is a useful way to restrict the behaviour of-null semantic items like pronouns using the information generated by-the index counting mechanism. The problem with null semantic items -is that their indices are not set, which means that they could-potentially combine with any other tree. To make things more -efficient, we can set the index of these items and thus reduce the-number of spurious combinations. --Notes-\begin{itemize}-%\item These combinations could produce false results if the-%input has to use multiple pronouns. For example, if you wanted to say-%something like \natlang{John promises Mary to convince Paul to give her-% his book}, these combinations could instead produce \natlang{give him-% \textbf{her} book}.-\item This function works by FS unification on the root node of the- tree with the \fs{\it idx:i\\}. If unification is not possible, - we simply return the tree as is.-\item This function renames the tree by appending the index to its name-\end{itemize}--\begin{code}-assignIndex :: GeniVal -> TagElem -> TagElem -assignIndex i te =- let idxfs = [ AvPair __idx__ i ]- oldt = ttree te- oldr = root oldt- tfup = gup oldr- --- in case unifyFeat tfup idxfs of- Nothing -> te- Just (gup2, sub) -> replace sub $ te { ttree = newt }- where newt = rootUpd oldt $ oldr { gup = gup2 }-\end{code}---% ====================================================================-\section{Further optimisations}-% ====================================================================--\subsection{Lexical filtering} \label{fn:detectIdxConstraints}--Lexical filtering allows the user to constrain the lexical selection-to only those items that contain a certain property, for example, the-realising an item as a cleft.--The idea is that the user provides an input like-\verb$idxconstraints:[cleft:j]$,-which means that the lexical selection must include exactly one tree-with the property cleft:j in its interface. This mechanism works as-pre-processing step after lexical selection and before polarity-automaton construction, in conjuction with the ExtraPolarities-mechanism. What we do is--\begin{enumerate}-\item Preprocess the lexically selected trees; any tree which has a- a desired property (e.g. cleft:j) in its interface is assigned- a positive polarity for that property (+cleft:j)-\item Add all the index constraints as negative extra polarities (-cleft:j)-\end{enumerate}--Note: we assume the index constraints and interface are sorted; also, we-prefix the index constraint polarities with a ``.'' because they are likely to-be very powerful filters and we would like them to be used first.--\begin{code}-detectIdxConstraints :: Flist -> Flist -> PolMap -detectIdxConstraints cs interface =- let matches = intersect cs interface- matchStr = map idxConstraintKey matches- in Map.fromList $ zip matchStr ((repeat.ival) 1)--declareIdxConstraints :: Flist -> PolMap-declareIdxConstraints = Map.fromList . (map declare) where- declare c = (idxConstraintKey c, minusone)- minusone = ival (-1)--idxConstraintKey :: AvPair -> PolarityKey-idxConstraintKey = PolarityKey . ('.' :) . showAv-\end{code}--\subsection{Automatic detection}--Automatic detection is not an optimisation in itself, but a means to-make grammar development with polarities more convenient.--\paragraph{Which attributes should we use?} Our detection process looks for-attributes which are defined on \emph{all} subst and root nodes of the-lexically selected items. Note that this should typically give you the-\verb!cat! and \verb!idx! polarities.--\begin{code}-detectPolFeatures :: [TagElem] -> [String]-detectPolFeatures tes =- let -- only initial trees need be counted; in aux trees, the- -- root node is implicitly canceled by the foot node- rfeats, sfeats :: [Flist]- rfeats = map (gdown.root.ttree) $ filter (\t -> ttype t == Initial) tes- sfeats = [ concat s | s <- map substTops tes, (not.null) s ]- --- attrs :: Flist -> [String]- attrs avs = [ a | AvPair a v <- avs, isConst v ]- theAttributes = map attrs $ rfeats ++ sfeats- in if null tes then [] else foldr1 intersect theAttributes---- FIXME: temporary HACKY code - delete me as soon as possible (written--- 2006-03-30------ only initial trees need be counted; in aux trees, the--- root node is implicitly canceled by the foot node-detectSansIdx :: [TagElem] -> [TagElem]-detectSansIdx =- let rfeats t = (gdown.root.ttree) t- feats t | ttype t == Initial = concat $ rfeats t : substTops t- feats t = concat $ substTops t- attrs avs = [ a | AvPair a v <- avs, isConst v ]- hasIdx t = __idx__ `elem` (attrs.feats $ t) || (ttype t /= Initial && (null $ substTops t))- in filter (not.hasIdx)-\end{code}--\paragraph{The polarity values}-First the simplified explanation: we assign every tree with a $-1$ charge for-every category for every substitution node it has. Additionally, we assign-every initial tree with a $+1$ charge for the category of its root node. So-for example, the tree s(n$\downarrow$, cl$\downarrow$, v(aime), n$\downarrow$)-should have the following polarities: s +1, cl -1, n -2. These charges are-added to any that previously been defined in the grammar.--Now what really happens: we treat automaton polarities as intervals, not -as single integers! For the most part, nothing changes from the simplified-explanation. Where we added a $-1$ charge before, we now add a $(-1,-1)$-charge. Similarly, we where added a $+1$ charge, we now add $(1,1)$. So-what's the point of all this? It helps us deal with atomic disjunction.--\subparagraph{Atomic disjunction} Say we encounter a substitution node -whose category is either cl or n. What we do is add the polarities-$cl (-1,0), n (-1,0)$ which means that there are anywhere from -1 to -0 cl, and for n. -FIXME: What kind of sucks about all this though is that this slightly worsens-the filter because it allows for both cl and n to be $-1$ (or $0$) at the same-time. It would be nice to have some kind of mutual exclusion working.--\begin{code}-detectPols :: Set.Set PolarityAttr -> [TagElem] -> [TagElem]-detectPols attrs = map (detectPolsH attrs)--detectPolsH :: Set.Set PolarityAttr -> TagElem -> TagElem-detectPolsH polarityAttrs te =- let detectOrBust x1 x2 x3 x4 =- case detectPolarity x1 x2 x3 x4 of- PD_UserError e -> error $ e ++ " in " ++ tgIdName te -- ideally we'd propagate this- PD_Nothing -> []- PD_Just p -> p- --- rup = gup . root .ttree $ te- rdown = gdown . root . ttree $ te- --- catAttr = SimplePolarityAttr "cat"- rstuffLite = concatMap (\v -> detectOrBust 1 v rup rdown)- $ Set.toList $ Set.delete catAttr polarityAttrs- rstuff :: [(PolarityKey,Interval)]- rstuff = if Set.member catAttr polarityAttrs- then -- cat is considered global to the whole tree to be- -- robust, we grab it from the top feature- detectOrBust 1 catAttr rup rup ++ rstuffLite- else rstuffLite- substuff :: [(PolarityKey,Interval)]- substuff = let tops = substTops te- detect :: PolarityAttr -> [(PolarityKey,Interval)]- detect v = concat $ zipWith (detectOrBust (-1) v) tops tops- in concatMap detect $ Set.toList polarityAttrs- -- substs and roots- pols = case ttype te of- Initial -> substuff ++ rstuff- _ -> substuff- --- oldfm = tpolarities te- in te { tpolarities = foldr addPol oldfm pols }--__cat__, __idx__ :: String-__cat__ = "cat"-__idx__ = "idx"---data PolarityDetectionResult = PD_UserError String- | PD_Nothing- | PD_Just [ (PolarityKey, Interval) ]---- | Careful, this completely ignores any user errors-pdJusts :: [PolarityDetectionResult] -> [(PolarityKey,Interval)]-pdJusts = concatMap helper- where helper (PD_Just x) = x- helper _ = []--detectPolarity :: Int -- ^ polarity to assign- -> PolarityAttr -- ^ attribute to look for- -> Flist -- ^ feature structure to filter on- -> Flist -- ^ feature structure to get value from- -> PolarityDetectionResult-detectPolarity i (RestrictedPolarityAttr cat att) filterFl fl =- case [ v | AvPair a v <- filterFl, a == __cat__ ] of- [] -> PD_UserError $ "[polarities] No category " ++ cat ++ " in:" ++ showFlist filterFl- [v] -> if isJust (unify [GConst [cat]] [v])- then detectPolarityForAttr i att fl- else PD_Nothing- _ -> PD_UserError $ "[polarities] More than one category " ++ " in:" ++ showFlist filterFl-detectPolarity i (SimplePolarityAttr att) _ fl = detectPolarityForAttr i att fl--detectPolarityForAttr :: Int -- ^ polarity to assign- -> String- -> Flist- -> PolarityDetectionResult-detectPolarityForAttr i att fl =- case [ v | AvPair a v <- fl, a == att ] of- [] -> PD_UserError $ "[polarities] No value for attribute: " ++ att ++ " in:" ++ showFlist fl- [v] -> if isConst v- then PD_Just $ case prefixWith att (fromGConst v) of- [x] -> [ (PolarityKey x, ival i) ] -- singleton- xs -> map (\x -> (PolarityKey x, toZero i)) xs -- interval if ambiguous- else PD_UserError $ "[polarities] Non-constant value for attribute: " ++ att ++ " in:" ++ showFlist fl- _ -> PD_UserError $ "[polarities] More than one value for attribute: " ++ att ++ " in:" ++ showFlist fl--toZero :: Int -> Interval-toZero x | x < 0 = (x, 0)- | otherwise = (0, x)--prefixWith :: String -> [String] -> [String]-prefixWith att = map (\x -> att ++ ('_' : x))--substNodes :: TagElem -> [GNode]-substNodes t = [ gn | gn <- (flatten.ttree) t, gtype gn == Subs ]--substTops :: TagElem -> [Flist]-substTops = map gup . substNodes-\end{code}--\subsection{Chart sharing}--Chart sharing is based on the idea that instead of performing a -seperate generation task for each automaton path, we should do-single generation task, but annotate each tree with set of the-automata paths it appears on. We then allow trees on the-same paths to be compared only if they are on the same path.-Note: chart sharing involves some mucking around with the generation-engine (see page \pageref{fn:Builder:preInit})--\begin{code}--- | Given a list of paths (i.e. a list of list of trees)--- return a list of trees such that each tree is annotated with the paths it--- belongs to.-detectPolPaths :: [[TagElem]] -> [(TagElem,BitVector)]-detectPolPaths paths = - let pathFM = detectPolPaths' Map.empty 0 paths- lookupTr k = Map.findWithDefault 0 k pathFM- in map (\k -> (k, lookupTr k)) $ Map.keys pathFM--type PolPathMap = Map.Map TagElem BitVector-detectPolPaths' :: PolPathMap -> Int -> [[TagElem]] -> PolPathMap --detectPolPaths' accFM _ [] = accFM-detectPolPaths' accFM counter (path:ps) = - let currentBits = shiftL 1 counter -- shift counter times the 1 bit- fn f [] = f- fn f (t:ts) = fn (Map.insertWith (.|.) t currentBits f) ts - newFM = fn accFM path- in detectPolPaths' newFM (counter+1) ps---- | Render the list of polarity automaton paths as a string-showPolPaths :: BitVector -> String-showPolPaths paths =- let pathlist = showPolPaths' paths 1- in concat $ intersperse ", " $ map show pathlist--showPolPaths' :: BitVector -> Int -> [Int] -showPolPaths' 0 _ = []-showPolPaths' bv counter = - if b then (counter:next) else next- where b = testBit bv 0- next = showPolPaths' (shiftR bv 1) (counter + 1)-\end{code}--\subsection{Semantic sorting}--To minimise the number of states in the polarity automaton, we could-also sort the literals in the target semantics by the number of-corresponding lexically selected items. The idea is to delay branching-as much as possible so as to mimimise the number of states in the-automaton.--Let's take a hypothetical example with two semantic literals:-bar (having two trees with polarties 0 and +1).-foo (having one tree with polarity -1) and-If we arbitrarily explored bar before foo (no semantic sorting), the-resulting automaton could look like this:--\begin{verbatim}- bar foo-(0)--+---(0)------(-1)- | - +---(1)------(0)-\end{verbatim}--With semantic sorting, we would explore foo before bar because foo has-fewer items and is less likely to branch. The resulting automaton-would have fewer states.--\begin{verbatim}- foo bar-(0)-----(-1)--+---(-1)- | - +---(0)-\end{verbatim}--The hope is that this would make the polarity automata a bit-faster to build, especially considering that we are working over-multiple polarity keys. --Note: we have to take care to count each literal for each lexical-entry's semantics or else the multi-literal semantic code will choke.--\begin{code}-sortSemByFreq :: Sem -> [TagElem] -> Sem-sortSemByFreq tsem cands = - let counts = map lenfn tsem - lenfn l = length $ filter fn cands - where fn x = l `elem` (tsemantics x)- -- note: we introduce an extra hack to push- -- index-counted extra columns to the end; just for UI reasons- sortfn a b - | isX a && isX b = compare (snd a) (snd b)- | isX a = GT- | isX b = LT- | otherwise = compare (snd a) (snd b)- where isX = isExtraCol.fst - sorted = sortBy sortfn $ zip tsem counts - in (fst.unzip) sorted -\end{code}--% -----------------------------------------------------------------------\section{Types}-% ------------------------------------------------------------------------\begin{code}-type SemMap = Map.Map Pred [TagElem]-type PolMap = Map.Map PolarityKey Interval---- | Adds a new polarity item to a 'PolMap'. If there already is a polarity--- for that item, it is summed with the new polarity.-addPol :: (PolarityKey,Interval) -> PolMap -> PolMap-addPol (p,c) m = Map.insertWith (!+!) p c m---- | Ensures that all states and transitions in the polarity automaton--- are unique. This is a slight optimisation so that we don't have to--- repeatedly check the automaton for state uniqueness during its--- construction, but it is essential that this check be done after--- construction-nubAut :: (Ord ab, Ord st) => NFA st ab -> NFA st ab -nubAut aut = - aut {- transitions = Map.map (\e -> Map.map nub e) (transitions aut)- }-\end{code}--\subsection{Polarity NFA}--We can define the polarity automaton as a NFA, or a five-tuple -$(Q, \Sigma, \delta, q_0, q_n)$ such that --\begin{enumerate}-\item $Q$ is a set of states, each state being a tuple $(i,e,p)$ where $i$-is an integer (representing a single literal in the target semantics), -$e$ is a list of extra literals-which are known by the state, and $p$ is a polarity.-\item $\Sigma$ is the union of the sets of candidate trees for all-propositions-\item $q_0$ is the start state $(0,[0,0])$ which does not correspond to any-propositions and is used strictly as a starting point.-\item $q_n$ is the final state $(n,[x,y])$ which corresponds to the last-proposition, with polarity $x \leq 0 \leq y$.-\item $\delta$ is the transition function between states, which we-define below.-\end{enumerate}--Note: -\begin{itemize}-\item For convenience during automaton intersection, we actually define- the states as being $(i, [(p_x,p_y)])$ where $[(p_x,p_y)]$ is a list of- polarity intervals. -\item We use integer $i$ for each state instead of literals directly,- because it is possible for the target semantics to contain the - same literal twice (at least, with the index counting mechanism- in place)-\end{itemize}--\begin{code}-data PolState = PolSt Int [Pred] [(Int,Int)] - -- ^ position in the input semantics, extra semantics, - -- polarity interval- deriving (Eq)-type PolTrans = TagElem-type PolAut = NFA PolState PolTrans-type PolTransFn = Map.Map PolState (Map.Map PolState [Maybe PolTrans])--instance Show PolState- where show (PolSt pr ex po) = show pr ++ " " ++ showSem ex ++ show po--- showPred pr ++ " " ++ showSem ex ++ show po--instance Ord PolState where- compare (PolSt pr1 ex1 po1) (PolSt pr2 ex2 po2) = - let prC = compare pr1 pr2- expoC = compare (ex1,po1) (ex2,po2)- in if (prC == EQ) then expoC else prC-\end{code}--We include also some fake states which are useful for general-housekeeping during the main algortihms.--\begin{code}-fakestate :: Int -> [Interval] -> PolState-fakestate s pol = PolSt s [] pol --PolSt (0, s, [""]) [] pol---- | an initial state for polarity automata-polstart :: [Interval] -> PolState-polstart pol = fakestate 0 pol -- fakestate "START" pol-\end{code}--% -----------------------------------------------------------------------\section{Display code}-\label{sec:display_pol}-% ------------------------------------------------------------------------\begin{code}--- | 'showLite' is like Show but it's only used for debugging--- TODO: is this true?-class ShowLite a where- showLite :: a -> String--instance (ShowLite a) => ShowLite [a] where- showLite x = "[" ++ (concat $ intersperse ", " $ map showLite x) ++ "]"-instance (ShowLite a, ShowLite b) => ShowLite (a,b) where- showLite (x,y) = "(" ++ (showLite x) ++ "," ++ (showLite y) ++ ")"--instance ShowLite Int where showLite = show -instance ShowLite Char where showLite = show -\end{code}--%\begin{code}-%instance (Show st, ShowLite ab) => ShowLite (NFA st ab) where-% showLite aut = -% concatMap showTrans $ toList (transitions aut)-% where showTrans ((st1, x), st2) = show st1 ++ showArrow x -% ++ show st2 ++ "\n"-% showArrow x = " --" ++ showLite x ++ "--> " -% -- showSt (PolSt pr po) = show po-%\end{code}--\begin{code}-instance ShowLite TagElem where- showLite = idname --{---- | Display a SemMap in human readable text.-showLiteSm :: SemMap -> String-showLiteSm sm = - concatMap showPair $ toList sm - where showPair (pr, cs) = showPred pr ++ "\t: " ++ showPair' cs ++ "\n"- showPair' [] = ""- showPair' (te:cs) = tlIdname te ++ "[" ++ showLitePm (tpolarities te) ++ "]"- ++ " " ++ showPair' cs --}---- | Display a PolMap in human-friendly text.--- The advantage is that it displays fewer quotation marks.-showLitePm :: PolMap -> String-showLitePm pm = - let showPair (f, pol) = showInterval pol ++ fromPolarityKey f- in concat $ intersperse " " $ map showPair $ Map.toList pm-\end{code}
+ src/NLP/GenI/Polarity/Internal.hs view
@@ -0,0 +1,190 @@+-- GenI surface realiser+-- Copyright (C) 2009 Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++{-# LANGUAGE OverloadedStrings #-}+module NLP.GenI.Polarity.Internal where++import Control.Applicative+import Data.List+import Data.Maybe (isJust)+import Data.Text (Text)+import Data.Tree (flatten)+import qualified Data.Map as Map+import qualified Data.Set as Set+import qualified Data.Text as T++import Data.FullList hiding ( (++) )+import NLP.GenI.Automaton+import NLP.GenI.FeatureStructure+import NLP.GenI.General+import NLP.GenI.GeniVal+import NLP.GenI.Polarity.Types+import NLP.GenI.Pretty+import NLP.GenI.Semantics (Literal)+import NLP.GenI.Tag ( TagElem(..), TagItem(..) )+import NLP.GenI.TreeSchema+ ( Ptype(Initial)+ , GNode, root, gup, gdown, gtype, GType(Subs),+ )++data PolarityDetectionResult = PD_UserError String+ | PD_Nothing+ | PD_Just [ (PolarityKey, Interval) ]+ | PD_Unconstrained (Text, Interval)++-- ----------------------------------------------------------------------+-- polarity detection+-- ----------------------------------------------------------------------++-- | Given a description of what the root feature should unify with+-- return a -1 polarity for all relevant polarity keys. This allows+-- us to compensate for the root node of any derived tree. +detectRootCompensation :: Set.Set PolarityAttr -> FeatStruct GeniVal -> PolMap+detectRootCompensation polarityAttrs rootFeat =+ Map.fromListWith (!+!) . pdResults+ $ map (\v -> detectPolarity (-1) (SimplePolarityAttr (pAttr v)) emptyFeatStruct rootFeat)+ $ Set.toList polarityAttrs+ where+ pAttr p@(SimplePolarityAttr _) = spkAtt p+ pAttr p@(RestrictedPolarityAttr _ _) = rpkAtt p++detectPolsH :: Set.Set PolarityAttr -> TagElem -> [(PolarityKey,Interval)]+detectPolsH polarityAttrs te =+ case ttype te of+ Initial -> substuff ++ rstuff+ _ -> substuff+ where+ pdError e = e ++ " in " ++ T.unpack (tgIdName te) -- ideally we'd propagate this+ detectOrBust x1 x2 x3 x4 = pdToList pdError (detectPolarity x1 x2 x3 x4)+ --+ rup = mkFeatStruct . gup . root .ttree $ te+ rdown = mkFeatStruct . gdown . root . ttree $ te+ --+ catAttr = SimplePolarityAttr "cat"+ rstuffLite = concatMap (\v -> detectOrBust 1 v rup rdown)+ $ Set.toList $ Set.delete catAttr polarityAttrs+ rstuff = if Set.member catAttr polarityAttrs+ then -- cat is considered global to the whole tree,+ -- but to be robust, we grab it from the top feature+ detectOrBust 1 catAttr rup rup ++ rstuffLite+ else rstuffLite+ substuff = let tops = map mkFeatStruct (substTops te)+ detect :: PolarityAttr -> [(PolarityKey,Interval)]+ detect v = concat $ zipWith (detectOrBust (-1) v) tops tops+ in concatMap detect $ Set.toList polarityAttrs++detectPolarity :: Int -- ^ polarity to assign+ -> PolarityAttr -- ^ attribute to look for+ -> FeatStruct GeniVal -- ^ feature structure to filter on ('RestrictedPolarityAttr' only)+ -> FeatStruct GeniVal -- ^ feature structure to get value from+ -> PolarityDetectionResult+detectPolarity i (RestrictedPolarityAttr cat att) filterFl fl =+ case Map.lookup __cat__ filterFl of+ Nothing -> PD_UserError . T.unpack $ "[polarities] No category "+ `T.append` cat+ `T.append` " in:"+ `T.append` pretty filterFl+ Just v -> if isJust (unify [mkGConstNone cat] [v])+ then detectPolarity i (SimplePolarityAttr att) emptyFeatStruct fl+ else PD_Nothing+detectPolarity i (SimplePolarityAttr att) _ fl =+ case Map.lookup att fl of+ Nothing -> PD_Unconstrained (withZero att)+ Just v -> case fromFL <$> gConstraints v of+ Just [x] -> PD_Just [ (PolarityKeyAv att x, ival i) ] -- singleton+ Just xs -> PD_Just $ map (withZero . PolarityKeyAv att) xs -- interval if ambiguous+ Nothing -> PD_Unconstrained (withZero att)+ where+ withZero x = (x, toZero i)++toZero :: Int -> Interval+toZero x | x < 0 = (x, 0)+ | otherwise = (0, x)++substNodes :: TagElem -> [GNode GeniVal]+substNodes t = [ gn | gn <- (flatten.ttree) t, gtype gn == Subs ]++substTops :: TagElem -> [Flist GeniVal]+substTops = map gup . substNodes++type SemMap = Map.Map (Literal GeniVal) [TagElem]+type PolMap = Map.Map PolarityKey Interval++-- ----------------------------------------------------------------------+-- after polarity detection+-- ----------------------------------------------------------------------++polarityKeys :: [TagElem] -> PolMap -> [PolarityKey]+polarityKeys cands extraPol =+ sortBy (flip compare) $ nub $ ksCands ++ ksExtra+ where+ ksCands = concatMap (Map.keys . tpolarities) cands+ ksExtra = Map.keys extraPol++-- | Convert any unconstrained polarities in a 'PolMap' to constrained+-- ones, assuming a global list of known constrained keys.+convertUnconstrainedPolarities :: [PolarityKey] -> PolMap -> PolMap+convertUnconstrainedPolarities ks pmap =+ addPols expansions con+ where+ (con, uncon) = Map.partitionWithKey constrained pmap+ constrained (PolarityKeyVar _) _ = False+ constrained _ _ = True+ --+ expansions = [ (k,v) | (PolarityKeyVar a, v) <- Map.toList uncon+ , k@(PolarityKeyAv a2 _) <- ks+ , a == a2+ ]++-- ----------------------------------------------------------------------+-- helpers+-- ----------------------------------------------------------------------++-- duplicates are a matter of course+addPols :: [(PolarityKey,Interval)] -> PolMap -> PolMap +addPols pols m = foldr f m pols+ where+ f (p,c) = Map.insertWith (!+!) p c++-- | Ensures that all states and transitions in the polarity automaton+-- are unique. This is a slight optimisation so that we don't have to+-- repeatedly check the automaton for state uniqueness during its+-- construction, but it is essential that this check be done after+-- construction+nubAut :: (Ord ab, Ord st) => NFA st ab -> NFA st ab+nubAut aut =+ aut {+ transitions = Map.map (\e -> Map.map nub e) (transitions aut)+ }++__cat__, __idx__ :: Text+__cat__ = "cat"+__idx__ = "idx"+++-- | Note that this will crash if any of the entries are errors+pdResults :: [PolarityDetectionResult] -> [(PolarityKey, Interval)]+pdResults = concatMap (pdToList id)++-- | Note that this will crash if any of the entries are errors+pdToList :: (String -> String) -- ^ on error message+ -> PolarityDetectionResult+ -> [(PolarityKey,Interval)]+pdToList _ (PD_Just x) = x+pdToList f (PD_UserError e) = error (f e)+pdToList _ (PD_Unconstrained (k,i)) = [ (PolarityKeyVar k, i) ]+pdToList _ PD_Nothing = []
+ src/NLP/GenI/Polarity/Types.hs view
@@ -0,0 +1,84 @@+-- GenI surface realiser+-- Copyright (C) 2009 Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}++module NLP.GenI.Polarity.Types where++import qualified Data.Set as Set+import Data.Generics ( Data )+import Data.Typeable ( Typeable )+import Data.Text ( Text )+import qualified Data.Text as T++import Control.DeepSeq++import NLP.GenI.Pretty++data PolarityKey = PolarityKeyAv Text Text+ | PolarityKeyStr Text+ | PolarityKeyVar Text -- ^ attribute+ deriving (Eq, Ord, Data, Typeable)++instance Pretty PolarityKey where+ pretty (PolarityKeyAv a v) = a <> ":" <> v+ pretty (PolarityKeyStr s) = s+ pretty (PolarityKeyVar a) = a <> ":_"++type SemPols = [Int]++-- | 'PolarityAttr' is something you want to perform detect polarities on.+data PolarityAttr = SimplePolarityAttr { spkAtt :: Text }+ -- | 'RestrictedPolarityKey' @c att@ is a polarity key in which we only pay+ -- attention to nodes that have the category @c@. This makes it possible+ -- to have polarities for a just a small subset of nodes+ | RestrictedPolarityAttr { _rpkCat :: Text, rpkAtt :: Text }+ deriving (Eq, Ord, Typeable)++readPolarityAttrs :: String -> Set.Set PolarityAttr+readPolarityAttrs = Set.fromList . map helper . words+ where+ helper s = case break (== '.') s of+ (a,"") -> SimplePolarityAttr (T.pack a)+ (c,a) -> RestrictedPolarityAttr (T.pack c) (T.pack (drop 1 a))++showPolarityAttrs :: Set.Set PolarityAttr -> String+showPolarityAttrs = unwords . map show . Set.toList++instance Show PolarityAttr where+ show (SimplePolarityAttr a) = T.unpack a+ show (RestrictedPolarityAttr c a) = T.unpack c ++ "." ++ T.unpack a++{-!+deriving instance NFData PolarityKey+deriving instance NFData PolarityAttr+!-}+-- GENERATED START++ +instance NFData PolarityKey where+ rnf (PolarityKeyAv x1 x2) = rnf x1 `seq` rnf x2 `seq` ()+ rnf (PolarityKeyStr x1 ) = rnf x1 `seq` ()+ rnf (PolarityKeyVar x1 ) = rnf x1 `seq` ()++ +instance NFData PolarityAttr where+ rnf (SimplePolarityAttr x1) = rnf x1 `seq` ()+ rnf (RestrictedPolarityAttr x1 x2) = rnf x1 `seq` rnf x2 `seq` ()+-- GENERATED STOP
− src/NLP/GenI/PolarityTypes.hs
@@ -1,44 +0,0 @@--- GenI surface realiser--- Copyright (C) 2009 Eric Kow------ This program is free software; you can redistribute it and/or--- modify it under the terms of the GNU General Public License--- as published by the Free Software Foundation; either version 2--- of the License, or (at your option) any later version.------ This program is distributed in the hope that it will be useful,--- but WITHOUT ANY WARRANTY; without even the implied warranty of--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the--- GNU General Public License for more details.------ You should have received a copy of the GNU General Public License--- along with this program; if not, write to the Free Software--- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.--module NLP.GenI.PolarityTypes where--import Data.List ( break )-import qualified Data.Set as Set-import Data.Generics ( Data )-import Data.Typeable ( Typeable )--newtype PolarityKey = PolarityKey { fromPolarityKey :: String } deriving (Show, Eq, Ord, Data, Typeable)---- | 'PolarityAttr' is something you want to perform detect polarities on.-data PolarityAttr = SimplePolarityAttr { spkAtt :: String }- -- | 'RestrictedPolarityKey' @c att@ is a polarity key in which we only pay- -- attention to nodes that have the category @c@. This makes it possible- -- to have polarities for a just a small subset of nodes- | RestrictedPolarityAttr { _rpkCat :: String, rpkAtt :: String }- deriving (Eq, Ord, Typeable)--readPolarityAttrs :: String -> Set.Set PolarityAttr-readPolarityAttrs = Set.fromList . map helper . words- where- helper s = case break (== '.') s of- (a,"") -> SimplePolarityAttr a- (c,a) -> RestrictedPolarityAttr c (drop 1 a)--instance Show PolarityAttr where- show (SimplePolarityAttr a) = a- show (RestrictedPolarityAttr c a) = c ++ "." ++ a
+ src/NLP/GenI/Pretty.hs view
@@ -0,0 +1,88 @@+-- GenI surface realiser+-- Copyright (C) 2012 Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}++-- | This is not a proper pretty printer. I aim is to replace this with a+-- (de-facto) standard library if one should appear+module NLP.GenI.Pretty where++import Data.Text ( Text )+import qualified Data.Text as T++-- | An alternative 'Show' instance (the idea being that we+-- should reserve 'Show' for outputting actual Haskell)+--+-- Minimal implementation is 'pretty' or 'prettyStr'+class Pretty a where+ pretty :: a -> Text+ pretty = T.pack . prettyStr++ prettyStr :: a -> String+ prettyStr = T.unpack . pretty++instance Pretty String where+ prettyStr a = a++instance Pretty Int where+ prettyStr a = show a++instance Pretty Integer where+ prettyStr a = show a++between :: Text -> Text -> Text -> Text+between l r x = l `T.append` x `T.append` r++parens :: Text -> Text+parens = between "(" ")"++squares :: Text -> Text+squares = between "[" "]"++-- | Identical to 'T.append'+(<>) :: Text -> Text -> Text+t1 <> t2 = t1 `T.append` t2++-- | Separated by space unless one of them is empty (in which case just+-- the non-empty one)+(<+>) :: Text -> Text -> Text+t1 <+> t2 | T.null t1 = t2+ | T.null t2 = t1+ | otherwise = t1 `T.append` " " `T.append` t2++-- | I think I want ($+$) here but I'm not sure I understand the+-- documentation from the pretty package.+--+-- @t1 `above` t2@ separates the two by a newline, unless one+-- of them is empty. The vertical equivalent to '(<+>)'+above :: Text -> Text -> Text+above t1 t2 | T.null t1 = t2+ | T.null t2 = t1+ | otherwise = t1 `T.append` "\n" `T.append` t2++-- |+--+-- > prettyCount toBlah "" (x,1) == "blah"+-- > prettyCount toBlah "foos" (x,1) == "blah"+-- > prettyCount toBlah "" (x,4) == "blah ×4"+-- > prettyCount toBlah "foos" (x,4) == "blah ×4 foos"+prettyCount :: (a -> Text) -> Text -> (a, Int) -> Text+prettyCount f _ (x, 1) = f x+prettyCount f ts (x, n) = f x <+> count <+> ts+ where+ count = '×' `T.cons` T.pack (show n)
− src/NLP/GenI/Regression.hs
@@ -1,83 +0,0 @@--- GenI surface realiser--- Copyright (C) 2009 Eric Kow------ This program is free software; you can redistribute it and/or--- modify it under the terms of the GNU General Public License--- as published by the Free Software Foundation; either version 2--- of the License, or (at your option) any later version.------ This program is distributed in the hope that it will be useful,--- but WITHOUT ANY WARRANTY; without even the implied warranty of--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the--- GNU General Public License for more details.------ You should have received a copy of the GNU General Public License--- along with this program; if not, write to the Free Software--- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.---- | Just regression testing of suites--- This can be seen as regression testing of GenI--- and also of grammars using GenI--module NLP.GenI.Regression (regressionGeni) where--import Control.Monad-import Data.IORef(readIORef, modifyIORef)-import Data.List(sort)-import Test.HUnit.Text (runTestTT)-import qualified Test.HUnit.Base as H-import Test.HUnit.Base ((@?))--import NLP.GenI.Btypes- ( SemInput, showSem- , TestCase(tcSem, tcName, tcExpected)- )-import qualified NLP.GenI.Btypes as G-import NLP.GenI.General- ( fst3,- )-import NLP.GenI.Geni-import NLP.GenI.Configuration- ( Params- , builderType , BuilderType(..)- )-import qualified NLP.GenI.Builder as B-import NLP.GenI.Simple.SimpleBuilder--regressionGeni :: ProgStateRef -> IO ()-regressionGeni pstRef = do- do pst <- readIORef pstRef- loadEverything pstRef- tests <- (mapM toTest) . tsuite $ pst- runTestTT . (H.TestList) . concat $ tests- return ()- where- toTest :: G.TestCase -> IO [H.Test] -- ^ GenI test case to HUnit Tests- toTest tc = -- run the case, and return a test case for each expected result- do res <- runOnSemInput pstRef (tcSem tc)- let sentences = map lemmaSentenceString res- name = tcName tc- semStr = showSem . fst3 . tcSem $ tc- mainMsg = "for " ++ semStr ++ ", got no results"- mainCase = H.TestLabel name- $ H.TestCase $ (not.null $ sentences) @? mainMsg- subMsg e = "for " ++ semStr ++ ", failed to get (" ++ e ++ ")"- subCase e = H.TestLabel name- $ H.TestCase $ (e `elem` sentences) @? subMsg e- return $ (mainCase :) $ map subCase (tcExpected tc)---- | Runs a case in the test suite. If the user does not specify any test--- cases, we run the first one. If the user specifies a non-existing--- test case we raise an error.-runOnSemInput :: ProgStateRef -> SemInput -> IO [GeniResult]-runOnSemInput pstRef semInput =- do modifyIORef pstRef (\x -> x{ts = semInput})- pst <- readIORef pstRef- let config = pa pst- go = case builderType config of- NullBuilder -> helper B.nullBuilder- SimpleBuilder -> helper simpleBuilder_2p- SimpleOnePhaseBuilder -> helper simpleBuilder_1p- sort `fmap` go- where- helper builder = fst3 `fmap` runGeni pstRef builder
+ src/NLP/GenI/Semantics.hs view
@@ -0,0 +1,267 @@+-- GenI surface realiser+-- Copyright (C) 2005-2009 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE TypeSynonymInstances, MultiParamTypeClasses, FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ViewPatterns #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+module NLP.GenI.Semantics where++import Control.Arrow ( first, (***), (&&&) )+import Control.Applicative ( (<$>) )+import Control.DeepSeq+import Data.Binary+import Data.Function ( on )+import Data.Data+import Data.List ( nub, sortBy, delete, insert )+import Data.Maybe ( isNothing, isJust, mapMaybe, fromMaybe )+import qualified Data.Map as Map+import Data.Text ( Text )+import qualified Data.Text as T++import NLP.GenI.FeatureStructure+import NLP.GenI.GeniShow+import NLP.GenI.General ( histogram )+import NLP.GenI.GeniVal+import NLP.GenI.Pretty++-- handle, predicate, parameters+data Literal gv = Literal+ { lHandle :: gv+ , lPredicate :: gv+ , lArgs :: [gv]+ }+ deriving (Eq, Data, Typeable)++instance Ord gv => Ord (Literal gv) where+ compare = compare `on` tucked+ where+ -- treat the handle as an argument+ tucked l = (lPredicate l, lHandle l : lArgs l)++type Sem = [Literal GeniVal]+type LitConstr = (Literal GeniVal, [Text])+type SemInput = (Sem,Flist GeniVal,[LitConstr])++instance Collectable a => Collectable (Literal a) where+ collect (Literal a b c) = collect a . collect b . collect c++emptyLiteral :: Literal GeniVal+emptyLiteral = Literal mkGAnon mkGAnon []++-- Utility functions++removeConstraints :: SemInput -> SemInput+removeConstraints (x, _, _) = (x, [], [])++-- | default sorting for a semantics+sortSem :: Ord a => [Literal a] -> [Literal a]+sortSem = sortBy compareOnLiteral++compareOnLiteral :: Ord a => Literal a -> Literal a -> Ordering+compareOnLiteral = compare++-- sort primarily putting the ones with the most constants first+-- and secondarily by the number of instances a predicate occurs+-- (if plain string; atomic disjunction/vars treated as infinite)+sortByAmbiguity :: Sem -> Sem+sortByAmbiguity sem = sortBy (flip compare `on` criteria) sem+ where+ criteria = (constants &&& ambiguity) -- this is reverse sorting+ -- so high numbers come first+ ambiguity l = fromMaybe 0 $ do -- Maybe+ p <- boringLiteral l+ negate <$> Map.lookup p (literalCount sem)++class HasConstants a where+ constants :: a -> Int++instance HasConstants GeniVal where+ constants g = if isConst2 g then 1 else 0+ where+ isConst2 :: GeniVal -> Bool+ isConst2 x = isJust (gConstraints x) && isNothing (gLabel x)++instance HasConstants a => HasConstants [a] where+ constants = sum . map constants++instance HasConstants (Literal GeniVal) where+ constants (Literal h p args) = constants (h:p:args)++literalCount :: [Literal GeniVal] -> Map.Map Text Int+literalCount = histogram . mapMaybe boringLiteral++boringLiteral :: Literal GeniVal -> Maybe Text+boringLiteral = singletonVal . lPredicate+ -- predicate with a straightfoward constant value+ -- exactly one constraint++-- Traversal++instance DescendGeniVal a => DescendGeniVal (Literal a) where+ descendGeniVal s (Literal h n lp) = Literal (descendGeniVal s h)+ (descendGeniVal s n)+ (descendGeniVal s lp)++-- Pretty printing++instance Pretty Sem where+ pretty = geniShowText++instance GeniShow Sem where+ geniShowText = squares . T.unwords . map geniShowText++instance Pretty (Literal GeniVal) where+ pretty = geniShowText++instance GeniShow (Literal GeniVal) where+ geniShowText (Literal h p l) =+ mh `T.append` geniShowText p+ `T.append` (parens . T.unwords . map geniShowText $ l)+ where+ mh = if hideh h then "" else geniShowText h `T.snoc` ':'+ hideh = maybe False isInternalHandle . singletonVal++instance Pretty SemInput where+ pretty = geniShowText++instance GeniShow SemInput where+ geniShowText (sem,icons,lcons) = T.intercalate "\n" . concat $+ [ [semStuff]+ , [ idxStuff | not (null icons) ]+ ]+ where+ semStuff = geniKeyword "semantics"+ . squares . T.unwords+ $ map withConstraints sem+ idxStuff = geniKeyword "idxconstraints"+ . squares+ $ geniShowText icons+ withConstraints lit =+ case concat [ cs | (p,cs) <- lcons, p == lit ] of+ [] -> geniShowText lit+ cs -> geniShowText lit `T.append` (squares . T.unwords $ cs)++isInternalHandle :: Text -> Bool+isInternalHandle = ("genihandle" `T.isPrefixOf`)++-- ----------------------------------------------------------------------+-- Subsumption+-- ----------------------------------------------------------------------++-- | @x `subsumeSem` y@ returns all the possible ways to unify+-- @x@ with some SUBSET of @y@ so that @x@ subsumes @y@.+-- If @x@ does NOT subsume @y@, we return the empty list.+subsumeSem :: Sem -> Sem -> [(Sem,Subst)]+subsumeSem x y | length x > length y = []+subsumeSem x y =+ map (first sortSem) $ subsumeSemH x y++subsumeSemH :: Sem -> Sem -> [(Sem,Subst)]+subsumeSemH [] [] = [ ([], Map.empty) ]+subsumeSemH _ [] = error "subsumeSemH: got longer list in front"+subsumeSemH [] _ = [ ([], Map.empty) ]+subsumeSemH (x:xs) ys = nub $+ do let attempts = zip ys $ map (subsumeLiteral x) ys+ (y, Just (x2, subst)) <- attempts+ let next_xs = replace subst xs+ next_ys = replace subst $ delete y ys+ prepend = insert x2 *** appendSubst subst+ prepend `fmap` subsumeSemH next_xs next_ys++-- | @p1 `subsumeLiteral` p2@... FIXME+subsumeLiteral :: Literal GeniVal -> Literal GeniVal -> Maybe (Literal GeniVal, Subst)+subsumeLiteral (Literal h1 p1 la1) (Literal h2 p2 la2) =+ if length la1 == length la2+ then do let hpla1 = h1:p1:la1+ hpla2 = h2:p2:la2+ (hpla, sub) <- hpla1 `allSubsume` hpla2+ return (toLiteral hpla, sub)+ else Nothing+ where+ toLiteral (h:p:xs) = Literal h p xs+ toLiteral _ = error "subsumeLiteral.toLiteral"++-- ----------------------------------------------------------------------+-- Unification+-- ----------------------------------------------------------------------++-- We return the list of minimal ways to unify two semantics.+-- By minimal, I mean that any literals that are not the product of a+-- succesful unification really do not unify with anything else.+unifySem :: Sem -> Sem -> [(Sem,Subst)]+unifySem xs ys =+ map (first sortSem) $+ if length xs < length ys+ then unifySemH xs ys+ else unifySemH ys xs++-- list monad for Prolog-style backtracking.+unifySemH :: Sem -> Sem -> [(Sem,Subst)]+unifySemH [] [] = return ([], Map.empty)+unifySemH [] xs = return (xs, Map.empty)+unifySemH xs [] = error $ "unifySem: shorter list should always be in front: " ++ prettyStr xs+unifySemH (x:xs) ys = nub $ do+ let attempts = zip ys $ map (unifyLiteral x) ys+ if all (isNothing . snd) attempts+ then first (x:) `fmap` unifySemH xs ys -- only include x unmolested if no unification succeeds+ else do (y, Just (x2, subst)) <- attempts+ let next_xs = replace subst xs+ next_ys = replace subst $ delete y ys+ prepend = insert x2 *** appendSubst subst+ prepend `fmap` unifySemH next_xs next_ys++unifyLiteral :: Literal GeniVal -> Literal GeniVal -> Maybe (Literal GeniVal, Subst)+unifyLiteral (Literal h1 p1 la1) (Literal h2 p2 la2) =+ if length la1 == length la2+ then do let hpla1 = h1:p1:la1+ hpla2 = h2:p2:la2+ (hpla, sub) <- hpla1 `unify` hpla2+ return (toLiteral hpla, sub)+ else Nothing+ where+ toLiteral (h:p:xs) = Literal h p xs+ toLiteral _ = error "unifyLiteral.toLiteral"++-- ----------------------------------------------------------------------+--+-- ----------------------------------------------------------------------++{-!+deriving instance NFData Literal +deriving instance Binary Literal +!-}++-- GENERATED START++ +instance NFData g => NFData (Literal g) where+ rnf (Literal x1 x2 x3) = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` ()++ +instance Binary g => Binary (Literal g) where+ put (Literal x1 x2 x3)+ = do put x1+ put x2+ put x3+ get+ = do x1 <- get+ x2 <- get+ x3 <- get+ return (Literal x1 x2 x3)+-- GENERATED STOP
+ src/NLP/GenI/Simple/SimpleBuilder.hs view
@@ -0,0 +1,937 @@+-- GenI surface realiser+-- Copyright (C) 2005 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, LiberalTypeSynonyms, DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}+module NLP.GenI.Simple.SimpleBuilder (+ -- Types+ Agenda, AuxAgenda, Chart, SimpleStatus, SimpleState,+ SimpleItem(..),++ -- From SimpleStatus+ simpleBuilder_1p, simpleBuilder_2p, simpleBuilder,+ theAgenda, theHoldingPen, theChart, theResults,+ initSimpleBuilder,+ addToAgenda, addToChart,+ genconfig,+ SimpleGuiItem(..),+ theTrash, step,++ unpackResult,++ -- * Aliases to non-exported functions+ testCanAdjoin, testIapplyAdjNode, testEmptySimpleGuiItem+ )+where++import Control.Arrow (first)+import Control.Monad (when, unless, liftM2)+import Control.Monad.State.Strict (get, put, modify, gets, runState, execStateT)+import Data.Bits+import Data.Generics ( Data )+import Data.List (partition, foldl', sortBy, unfoldr )+import Data.Maybe (isJust, isNothing, mapMaybe, fromMaybe)+import Data.Ord (comparing)+import Data.Text ( Text )+import Data.Tree+import qualified Data.Map as Map+import qualified Data.Text as T++import NLP.GenI.Automaton ( automatonPaths, NFA(..), addTrans )+import NLP.GenI.Builder ( incrCounter, num_iterations, num_comparisons+ , chart_size, SemBitMap, defineSemanticBits, semToBitVector, bitVectorToSem+ , DispatchFilter, (>-->), condFilter, FilterStatus(Filtered, NotFiltered)+ , GenStatus(..),+ )+import NLP.GenI.Configuration+import NLP.GenI.FeatureStructure ( unifyFeat, Flist )+import NLP.GenI.General ( BitVector, mapMaybeM, mapTree', geniBug, preTerminals, repList )+import NLP.GenI.GeniVal ( GeniVal, replace, DescendGeniVal(..), Subst, appendSubst )+import NLP.GenI.Morphology.Types ( LemmaPlus(..) )+import NLP.GenI.Pretty+import NLP.GenI.Semantics ( sortSem, Sem )+import NLP.GenI.Statistics (Statistics)+import NLP.GenI.Tag+ ( TagElem, TagSite(..), getLexeme, toTagSite+ , tidnum, idname, ttree, ttype, tsemantics+ , detectSites, TagDerivation, DerivationStep(..)+ , plugTree, spliceTree+ , ts_rootFeatureMismatch, ts_synIncomplete, ts_semIncomplete+ , ts_tbUnificationFailure+ )+import NLP.GenI.TreeSchema+ ( Ptype(Initial), GNode(..), NodeName, gnnameIs+ , GType(Other), root, foot )+import qualified NLP.GenI.Builder as B++-- --------------------------------------------------------------------+-- The Builder interface+-- --------------------------------------------------------------------++type SimpleBuilder = B.Builder SimpleStatus SimpleItem Params+simpleBuilder_2p, simpleBuilder_1p :: SimpleBuilder+simpleBuilder_2p = simpleBuilder True+simpleBuilder_1p = simpleBuilder False++simpleBuilder :: Bool -> SimpleBuilder+simpleBuilder twophase = me+ where+ me = B.Builder+ { B.init = initSimpleBuilder twophase+ , B.step = if twophase then generateStep_2p else generateStep_1p+ , B.stepAll = B.defaultStepAll me+ , B.finished = finished twophase+ , B.unpack = unpackResults.theResults+ , B.partial = unpackResults.partialResults+ }++-- --------------------------------------------------------------------+-- Key types+-- --------------------------------------------------------------------++type Agenda = [SimpleItem]+type AuxAgenda = [SimpleItem]+type Chart = [SimpleItem]+type Trash = [SimpleItem]++data GenerationPhase = SubstitutionPhase+ | AdjunctionPhase+ deriving (Show)++isAdjunctionPhase :: GenerationPhase -> Bool+isAdjunctionPhase AdjunctionPhase = True+isAdjunctionPhase _ = False++type SimpleState a = B.BuilderState SimpleStatus a++data SimpleStatus = S+ { theAgenda :: Agenda+ , theHoldingPen :: AuxAgenda+ , theChart :: Chart+ , theTrash :: Trash+ , theResults :: [SimpleItem]+ , tsem :: BitVector+ , step :: GenerationPhase+ , gencounter :: Integer+ , genconfig :: Params+ -- we keep a SemBitMap strictly to help display the semantics+ , semBitMap :: SemBitMap+ }+ -- deriving Show++-- SimpleStatus updaters++assignNewId :: SimpleItem -> SimpleState SimpleItem+assignNewId item = do+ modify $ \s -> s{ gencounter = gencounter s + 1 }+ counter <- gets gencounter+ return $ item { siId = counter }++addToAgenda :: SimpleItem -> SimpleState ()+addToAgenda te = do+ te2 <- assignNewId te+ modify $ \s -> s{theAgenda = te2 : theAgenda s }++updateAgenda :: Agenda -> SimpleState ()+updateAgenda a =+ modify $ \s -> s{theAgenda = a}++addToAuxAgenda :: SimpleItem -> SimpleState ()+addToAuxAgenda te = do+ te2 <- assignNewId te+ modify $ \s -> s { theHoldingPen = te2 : theHoldingPen s }++addToChart :: SimpleItem -> SimpleState ()+addToChart te = do+ modify $ \s -> s { theChart = te:theChart s+ }+ incrCounter chart_size 1++addToTrash :: SimpleItem -> String -> SimpleState ()+addToTrash te err = do+ disableGui <- gets (hasFlagP DisableGuiFlg . genconfig)+ unless disableGui $+ modify $ \s -> s { theTrash = te2 : theTrash s }+ where+ te2 = modifyGuiStuff (\g -> g { siDiagnostic = err : siDiagnostic g }) te++addToResults :: SimpleItem -> SimpleState ()+addToResults te =+ modify $ \s -> s { theResults = te : theResults s }++-- ----------------------------------------------------------------------+-- SimpleItem+-- ----------------------------------------------------------------------++data SimpleItem = SimpleItem+ { siId :: ChartId+ --+ , siSubstnodes :: [NodeName]+ , siAdjnodes :: [NodeName]+ --+ , siSemantics :: BitVector+ , siPolpaths :: BitVector+ -- for generation sans semantics+ -- , siAdjlist :: [(String,Integer)] -- (node name, auxiliary tree id)+ , siNodes :: [GNode GeniVal] -- ^ actually a set+ , siDerived :: Tree Text+ , siRoot_ :: NodeName+ , siFoot_ :: Maybe NodeName+ --+ , siPendingTb :: [NodeName] -- only for one-phase+ -- how was this item produced?+ , siDerivation :: TagDerivation+ -- for the debugger only+ , siGuiStuff :: SimpleGuiItem+ } -- deriving (Show)+++lookupOrBug :: Text -> SimpleItem -> NodeName -> GNode GeniVal+lookupOrBug fnname item k =+ case filter (gnnameIs k) (siNodes item) of+ [] -> geniBug $ T.unpack fnname ++ ": could not find node " ++ T.unpack k+ [gn] -> gn+ _ -> geniBug $ T.unpack fnname ++ ": more than one node named " ++ T.unpack k++siRoot :: SimpleItem -> TagSite+siRoot x = toTagSite . lookupOrBug "siRoot" x $ siRoot_ x++siFoot :: SimpleItem -> Maybe TagSite+siFoot x = (toTagSite . lookupOrBug "siFoot" x) `fmap` siFoot_ x++instance DescendGeniVal (Text, B.UninflectedDisjunction) where+ descendGeniVal m (s,d) = (s, descendGeniVal m d)++-- | Things whose only use is within the graphical debugger+data SimpleGuiItem = SimpleGuiItem+ { siHighlight :: [Text] -- ^ nodes to highlight+ -- if there are things wrong with this item, what?+ , siDiagnostic :: [String]+ , siFullSem :: Sem+ , siIdname :: Text+ } deriving (Data, Typeable)++emptySimpleGuiItem :: SimpleGuiItem+emptySimpleGuiItem = SimpleGuiItem [] [] [] ""++testEmptySimpleGuiItem :: SimpleGuiItem+testEmptySimpleGuiItem = emptySimpleGuiItem++modifyGuiStuff :: (SimpleGuiItem -> SimpleGuiItem) -> SimpleItem -> SimpleItem+modifyGuiStuff fn i = i { siGuiStuff = fn . siGuiStuff $ i }++type ChartId = Integer++instance DescendGeniVal SimpleItem where+ descendGeniVal s i = s `seq` i `seq`+ i { siNodes = descendGeniVal s (siNodes i) }++{-# INLINE closedAux #-}++-- | True if the chart item has no open substitution nodes+closed :: SimpleItem -> Bool+closed = null.siSubstnodes++-- | True if the chart item is an auxiliary tree+aux :: SimpleItem -> Bool+aux = isJust . siFoot++-- | True if both 'closed' and 'aux' are True+closedAux :: SimpleItem -> Bool+closedAux x = aux x && closed x++adjdone :: SimpleItem -> Bool+adjdone = null.siAdjnodes++siInitial :: SimpleItem -> Bool+siInitial = isNothing . siFoot++-- --------------------------------------------------------------------+-- Initialisation+-- --------------------------------------------------------------------++-- | Creates an initial SimpleStatus.+initSimpleBuilder :: Bool -> B.Input -> Params -> (SimpleStatus, Statistics)+initSimpleBuilder twophase input config =+ let disableGui = hasFlagP DisableGuiFlg config+ cands = map (initSimpleItem disableGui bmap) $ B.inCands input+ (sem,_,_) = B.inSemInput input+ bmap = defineSemanticBits sem+ -- FIXME: I don't know if this matters for one-phase+ -- because of on-the-fly tb unification (in 2p), we+ -- need an initial tb step that only addresses the+ -- nodes with null adjunction constraints+ simpleDp = if twophase then simpleDispatch_2p else simpleDispatch_1p+ initialDp = dpTbNaFailure >--> dpTbFailure >--> simpleDp+ --+ initS = S{ theAgenda = []+ , theHoldingPen = []+ , theChart = []+ , theTrash = []+ , theResults = []+ , semBitMap = bmap+ , tsem = semToBitVector bmap sem+ , step = SubstitutionPhase+ , gencounter = 0+ , genconfig = config }+ --+ in B.unlessEmptySem input config $+ runState (execStateT (mapM initialDp cands) initS) (B.initStats config)+++initSimpleItem :: Bool -- ^ disable gui+ -> SemBitMap -> (TagElem, BitVector) -> SimpleItem+initSimpleItem disableGui bmap (teRaw,pp) =+ let (te,tlite) = renameNodesWithTidnum teRaw in+ case detectSites (ttree te) of+ (snodes,anodes,nullAdjNodes) -> SimpleItem+ { siId = tidnum te+ , siSemantics = semToBitVector bmap (tsemantics te)+ , siSubstnodes = snodes+ , siAdjnodes = anodes+ , siPolpaths = pp+ -- for generation sans semantics+ -- , siAdjlist = []+ , siNodes = flatten.ttree $ te+ , siDerived = tlite+ , siRoot_ = gnname . root $ theTree+ , siFoot_ = if ttype te == Initial then Nothing else Just . gnname . foot $ theTree+ , siDerivation = [ InitStep (gorigin . root $ theTree) ]+ -- note: see comment in initSimpleBuilder re: tb unification+ , siPendingTb = nullAdjNodes+ --+ , siGuiStuff = if disableGui then emptySimpleGuiItem else initSimpleGuiItem te+ }+ where theTree = ttree te++initSimpleGuiItem :: TagElem -> SimpleGuiItem+initSimpleGuiItem te = SimpleGuiItem+ { siHighlight = []+ , siDiagnostic = []+ , siFullSem = tsemantics te+ , siIdname = idname te }++renameNodesWithTidnum :: TagElem -> (TagElem, Tree NodeName)+renameNodesWithTidnum te =+ ( te { ttree = mapTree' renameNode theTree }+ , mapTree' newName theTree+ )+ where+ theTree = ttree te+ renameNode n = n { gnname = newName n }+ newName n = gnname n `T.append` "-" `T.append` tidstr te+ tidstr = T.pack . show . tidnum++-- --------------------------------------------------------------------+-- Generate+-- --------------------------------------------------------------------++-- One-phase generation++generateStep_1p :: SimpleState ()+generateStep_1p =+ do isDone <- gets (null.theAgenda)+ let dispatch = mapM simpleDispatch_1p+ if isDone+ then return ()+ else do incrCounter num_iterations 1+ given <- selectGiven+ -- do both substitution and adjunction+ _ <- applySubstitution1p given >>= dispatch+ _ <- passiveAdjunction1p given >>= dispatch+ _ <- activeAdjunction1p given >>= dispatch+ _ <- sansAdjunction1p given >>= dispatch+ -- determine which of the res should go in the agenda+ -- (monadic state) and which should go in the result (res')+ addToChart given++-- Two-phase generation++generateStep_2p :: SimpleState ()+generateStep_2p = do+ nir <- gets (null.theAgenda)+ curStep <- gets step+ case curStep of+ SubstitutionPhase -> if nir then switchToAux else generateStep_2p_sub+ AdjunctionPhase -> if nir then return () else generateStep_2p_adj++generateStep_2p_sub :: SimpleState ()+generateStep_2p_sub =+ do incrCounter num_iterations 1+ -- choose an item from the agenda+ given <- selectGiven+ res <- applySubstitution given+ mapM_ simpleDispatch_2p res+ -- put the given into the chart untouched+ addToChart given++generateStep_2p_adj :: SimpleState ()+generateStep_2p_adj =+ do incrCounter num_iterations 1+ -- choose an item from the agenda+ given <- selectGiven+ res <- liftM2 (++) (applyAdjunction2p given) (sansAdjunction2p given)+ mapM_ simpleDispatch_2p_adjphase res+ when (adjdone given) $ trashIt given++-- Helpers for the generateSteps++trashIt :: SimpleItem -> SimpleState ()+trashIt item =+ do disableGui <- gets (hasFlagP DisableGuiFlg . genconfig)+ unless disableGui $ do+ s <- get+ let bmap = semBitMap s+ itemSem = siSemantics item+ inputSem = tsem s+ reason = if inputSem == itemSem+ then "unknown reason!"+ else ts_semIncomplete $ bitVectorToSem bmap $ inputSem `xor` itemSem+ addToTrash item reason++-- | Arbitrarily selects and removes an element from the agenda and+-- returns it.+selectGiven :: SimpleState SimpleItem+selectGiven = do+ agenda <- gets theAgenda+ case agenda of+ [] -> geniBug "null agenda in selectGiven"+ (a:atail) -> updateAgenda atail >> return a++-- Switching phases++switchToAux :: SimpleState ()+switchToAux = do+ st <- get+ let oldAuxTrees = theHoldingPen st+ -- You might be wondering why we ignore the auxiliary trees in the+ -- chart; this is because all the syntactically complete auxiliary+ -- trees have already been filtered away by calls to classifyNew+ initialT = filter siInitial (theChart st)+ (compT1, incompT1) = partition (null.siSubstnodes) initialT+ (auxTrees, compT2) =+ ( mapMaybe (detectNa oldAuxTrees) oldAuxTrees+ , mapMaybe (detectNa auxTrees) compT1 )+ (compT3, incompT3) = semfilter (tsem st) auxTrees compT2+ --+ compT = compT3+ put st{ theAgenda = []+ , theHoldingPen = []+ , theChart = auxTrees+ , step = AdjunctionPhase }+ mapM_ simpleDispatch_2p_adjphase compT+ -- toss the syntactically incomplete stuff in the trash+ mapM_ (\t -> addToTrash t ts_synIncomplete) incompT1+ mapM_ (\t -> addToTrash t "sem-filtered") incompT3++-- Completion++finished :: Bool -> SimpleStatus -> GenStatus+finished twophase st+ | reallyDone = B.Finished+ | atMaxResults = B.Finished+ | atMaxSteps = B.Error $ "Max steps exceeded" <+> parens (pretty maxSteps)+ | otherwise = B.Active+ where+ reallyDone = null (theAgenda st) && (not twophase || isAdjunctionPhase (step st)) + atMaxResults = maybeIf (<= fromIntegral (length (theResults st))) $ getFlagP MaxResultsFlg (genconfig st)+ atMaxSteps = maybeIf (< gencounter st) mMaxSteps+ mMaxSteps = getFlagP MaxStepsFlg (genconfig st)+ maxSteps = fromMaybe (error "get maxsteps") mMaxSteps+ maybeIf bf = maybe False bf++-- SemFilter Optimisation++semfilter :: BitVector -> [SimpleItem] -> [SimpleItem] -> ([SimpleItem], [SimpleItem])+semfilter inputsem auxs initial =+ let auxsem x = foldl' (.|.) 0 [ siSemantics a | a <- auxs, siPolpaths a .&. siPolpaths x /= 0 ]+ -- lite, here, means sans auxiliary semantics+ notjunk x = (siSemantics x) .&. inputsemLite == inputsemLite+ where inputsemLite = inputsem `xor` (auxsem x)+ -- note that we can't just compare against siSemantics because+ -- that would exclude trees that have stuff in the aux semantics+ -- which would be overzealous+ in partition notjunk initial++-- --------------------------------------------------------------------+-- Substitution+-- --------------------------------------------------------------------++applySubstitution :: SimpleItem -> SimpleState ([SimpleItem])+applySubstitution item =+ do gr <- lookupChart item+ active <- mapM (\x -> iapplySubst True item x) gr+ passive <- mapM (\x -> iapplySubst True x item) gr+ let res = concat $ active ++ passive+ incrCounter num_comparisons (2 * (length gr))+ return res++applySubstitution1p :: SimpleItem -> SimpleState ([SimpleItem])+applySubstitution1p item =+ do gr <- lookupChart item+ active <- if adjdone item then return []+ else mapM (\x -> iapplySubst False item x) gr+ passive <- mapM (\x -> iapplySubst False x item) $ filter adjdone gr+ let res = concat $ active ++ passive+ incrCounter num_comparisons (2 * (length gr))+ return res++-- | Note: returns ONE possible substitution (the head node)+-- of the first in the second. As all substitutions nodes should+-- be substituted we force substitution in order.+iapplySubst :: Bool -> SimpleItem -> SimpleItem -> SimpleState [SimpleItem]+iapplySubst twophase item1 item2 | siInitial item1 && closed item1 = {-# SCC "applySubstitution" #-}+ case siSubstnodes item2 of+ [] -> return []+ (shead : stail) ->+ let doIt =+ do -- Maybe monad+ let (TagSite n fu fd nOrigin) = toTagSite (lookupOrBug "iapplySubst" item2 shead)+ (TagSite rn ru rd rOrigin) = siRoot item1+ (newU, subst1) <- unifyFeat ru fu+ (newD, subst2) <- unifyFeat (replace subst1 rd)+ (replace subst1 fd)+ let subst = appendSubst subst1 subst2+ -- gui stuff+ newRoot g = g { gup = newU, gdown = newD, gtype = Other }+ let pending = if twophase then []+ else rn : (siPendingTb item1 ++ siPendingTb item2)+ let item1g = item1 { siNodes = repList (gnnameIs rn) newRoot (siNodes item1) }+ return $! replace subst $ combineSimpleItems [rn] item1g $+ item2 { siSubstnodes = stail ++ (siSubstnodes item1)+ , siAdjnodes = siAdjnodes item1 ++ siAdjnodes item2+ , siDerived = plugTree (siDerived item1) n (siDerived item2)+ , siDerivation = addToDerivation SubstitutionStep (item1, rOrigin) (item2,nOrigin,n)+ , siPendingTb = pending+ }+ in case doIt of+ Nothing -> return []+ Just x -> do incrCounter "substitutions" 1+ return [x]+iapplySubst _ _ _ = return []++-- --------------------------------------------------------------------+-- Adjunction+-- ---------------------------------------------------------------++applyAdjunction2p :: SimpleItem -> SimpleState ([SimpleItem])+applyAdjunction2p item = {-# SCC "applyAdjunction2p" #-}+ do gr <-lookupChart item+ incrCounter num_comparisons (length gr)+ mapMaybeM (\a -> tryAdj True a item) gr++passiveAdjunction1p :: SimpleItem -> SimpleState [SimpleItem]+passiveAdjunction1p item | closed item && siInitial item =+ do gr <- lookupChart item+ mapMaybeM (\a -> tryAdj False a item) $ filter validAux gr+passiveAdjunction1p _ = return []++activeAdjunction1p :: SimpleItem -> SimpleState [SimpleItem]+activeAdjunction1p item | validAux item =+ do gr <- lookupChart item+ mapMaybeM (\p -> tryAdj False item p) $ filter (\x -> siInitial x && closed x) gr+activeAdjunction1p _ = return []++validAux :: SimpleItem -> Bool+validAux t = closedAux t && adjdone t++tryAdj :: Bool -> SimpleItem -> SimpleItem -> SimpleState (Maybe SimpleItem)+tryAdj twophase aItem pItem =+ do case iapplyAdjNode twophase aItem pItem of+ Just x -> do incrCounter "adjunctions" 1+ return $ Just x+ Nothing -> return Nothing++-- | Ignore the next adjunction node+sansAdjunction1p, sansAdjunction2p :: SimpleItem -> SimpleState [SimpleItem]+sansAdjunction1p item | closed item =+ case siAdjnodes item of+ [] -> return []+ (ahead : atail) ->+ return $ [item { siAdjnodes = atail+ , siPendingTb = ahead : (siPendingTb item) } ]+sansAdjunction1p _ = return []++-- | Ignore the next adjunction node+sansAdjunction2p item | closed item =+ case siAdjnodes item of+ [] -> return []+ (ahead : atail) -> do+ let (TagSite gn t b _) = toTagSite (lookupOrBug "sansAdjunction2p" item ahead)+ -- do top/bottom unification on the node+ case unifyFeat t b of+ Nothing ->+ do addToTrash (modifyGuiStuff (\g -> g { siHighlight = [gn] }) item)+ ts_tbUnificationFailure+ return []+ Just (tb,s) ->+ let item1 = constrainAdj gn tb item+ in return $! [replace s $! item1 { siAdjnodes = atail }]+sansAdjunction2p _ = return []++iapplyAdjNode :: Bool -> SimpleItem -> SimpleItem -> Maybe SimpleItem+iapplyAdjNode twophase aItem pItem = {-# SCC "iapplyAdjNode" #-}+ case siAdjnodes pItem of+ [] -> Nothing+ (pHead : pTail) -> do+ -- let's go!+ let pSite = toTagSite (lookupOrBug "iapplyAdjNode" pItem pHead)+ (anr, anf, subst12) <- canAdjoin aItem pSite+ let r_name = siRoot_ aItem+ r = siRoot aItem+ f <- siFoot aItem+ let an_name = tsName pSite+ -- the new adjunction nodes+ aItem2 = aItem { siNodes = map (setSites anr) (siNodes aItem) }+ where+ setSites (TagSite n u d _) gn =+ if gnname gn == n then gn { gup = u, gdown = d } else gn+ rawCombined =+ combineSimpleItems [tsName r, an_name] aItem2 $ pItem+ { siAdjnodes = pTail ++ siAdjnodes aItem+ , siDerived = spliceTree (tsName f) (siDerived aItem) an_name (siDerived pItem)+ , siDerivation = addToDerivation AdjunctionStep (aItem,tsOrigin r) (pItem,tsOrigin pSite,an_name)+ -- , siAdjlist = (n, (tidnum te1)):(siAdjlist item2)+ -- if we adjoin into the root, the new root is that of the aux+ -- tree (affects 1p only)+ , siRoot_ = if isRootOf pItem an_name then r_name else siRoot_ pItem+ , siPendingTb =+ if twophase then []+ else tsName f : siPendingTb pItem ++ siPendingTb aItem+ }+ -- one phase = postpone tb unification+ -- two phase = do tb unification on the fly+ finalRes1p = return $ replace subst12 rawCombined+ finalRes2p =+ do -- tb on the former foot+ tbRes <- unifyFeat (tsUp anf) (tsDown anf)+ let (anf_tb, subst3) = tbRes+ myRes = constrainAdj an_name anf_tb res'+ -- apply the substitutions+ res' = replace (appendSubst subst12 subst3) rawCombined+ return myRes+ -- ---------------+ if twophase then finalRes2p else finalRes1p++testIapplyAdjNode :: Bool -> SimpleItem -> SimpleItem -> Maybe SimpleItem+testIapplyAdjNode = iapplyAdjNode++canAdjoin :: SimpleItem -> TagSite -> Maybe (TagSite, TagSite, Subst)+canAdjoin aItem pSite = do+ -- let's go!+ let r = siRoot aItem -- auxiliary tree, eh?+ f <- siFoot aItem -- should really be an error if fails+ (anr_up', subst1) <- unifyFeat (tsUp r) (tsUp pSite)+ (anf_down, subst2) <- unifyFeat (replace subst1 $ tsDown f) (replace subst1 $ tsDown pSite)+ let -- combined substitution list and success condition+ subst12 = appendSubst subst1 subst2+ anr = replace subst12 $ r { tsUp = anr_up' } -- resulting node based on the root node of the aux tree+ anf = replace subst12 $ f { tsDown = anf_down } -- resulting node based on the foot node of the aux tree+ return (anr, anf, subst12)++testCanAdjoin :: SimpleItem -> TagSite -> Maybe (TagSite, TagSite, Subst)+testCanAdjoin = canAdjoin++detectNa :: [SimpleItem] -- ^ aux trees+ -> SimpleItem -- ^ me+ -> Maybe SimpleItem+detectNa rawAux i = helper (map look (siAdjnodes i)) Map.empty []+ where+ look = toTagSite . lookupOrBug "detectNa" i+ compatAux = filterCompatible i rawAux+ helper [] s acc = Just $ replace s $ i { siAdjnodes = acc }+ helper (t:ts) s acc =+ let hasAdj = any isJust $ map (\a -> canAdjoin a t) compatAux+ in case (snd `fmap` unifyFeat (tsUp t) (tsDown t)) of+ Just s2 -> if hasAdj+ then helper ts s (tsName t : acc)+ else helper (replace s2 ts) (appendSubst s s2) acc+ Nothing -> if hasAdj+ then helper ts s (tsName t : acc)+ else Nothing++-- --------------------------------------------------------------------+-- Helper functions for operations+-- --------------------------------------------------------------------++isRootOf :: SimpleItem -> Text -> Bool+isRootOf item n = n == siRoot_ item++-- | Retrieves a list of trees from the chart which could be combined with the given agenda tree.+-- The current implementation searches for trees which+-- * do not have overlapping semantics with the given+-- * are on the some of the same polarity automaton paths as the+-- current agenda item+lookupChart :: SimpleItem -> SimpleState [SimpleItem]+lookupChart given = gets (filterCompatible given . theChart)++filterCompatible :: SimpleItem -> [SimpleItem] -> [SimpleItem]+filterCompatible given chart =+ [ i | i <- chart+ -- should be on the same polarity path (chart sharing)+ , (siPolpaths i) .&. gpaths /= 0+ -- semantics should not be overlapping+ && (siSemantics i .&. gsem ) == 0+ ]+ where+ gpaths = siPolpaths given+ gsem = siSemantics given++-- | Helper function for when chart operations succeed.+combineSimpleItems :: [NodeName] -- ^ nodes to highlight+ -> SimpleItem -> SimpleItem -> SimpleItem+combineSimpleItems hi item1 item2 = {-# SCC "combineSimpleItems" #-}+ item2 { siSemantics = siSemantics item1 .|. siSemantics item2+ , siPolpaths = siPolpaths item1 .&. siPolpaths item2+ , siGuiStuff = combineSimpleGuiItems hi (siGuiStuff item1) (siGuiStuff item2)+ , siNodes = siNodes item1 ++ siNodes item2+ }++combineSimpleGuiItems :: [NodeName]+ -> SimpleGuiItem -> SimpleGuiItem -> SimpleGuiItem+combineSimpleGuiItems hi item1 item2 =+ item2 { siFullSem = sortSem $ siFullSem item1 ++ siFullSem item2+ , siDiagnostic = siDiagnostic item1 ++ siDiagnostic item2+ , siHighlight = hi+ }++constrainAdj :: Text -> Flist GeniVal -> SimpleItem -> SimpleItem+constrainAdj gn newT g =+ g { siNodes = repList (gnnameIs gn) fixIt (siNodes g) }+ where fixIt n = n { gup = newT, gdown = [], gaconstr = True }++-- Derivation trees++addToDerivation :: (Text -> Text -> Text -> DerivationStep)+ -> (SimpleItem, Text)+ -> (SimpleItem, Text, Text)+ -> TagDerivation+addToDerivation op (tc,tcOrigin) (tp,tpOrigin,tpSite) =+ let hp = siDerivation tp+ hc = filter (not . isInit) (siDerivation tc)+ newnode = op tcOrigin tpOrigin tpSite+ in newnode:hp++hc+ where+ isInit :: DerivationStep -> Bool+ isInit (InitStep _) = True+ isInit _ = False++-- --------------------------------------------------------------------+-- Dispatching new results+-- --------------------------------------------------------------------++type SimpleDispatchFilter = DispatchFilter SimpleState SimpleItem++simpleDispatch_2p :: SimpleDispatchFilter+simpleDispatch_2p =+ simpleDispatch (dpRootFeatFailure >--> dpToResults)+ (dpAux >--> dpToAgenda)++simpleDispatch_2p_adjphase :: SimpleDispatchFilter+simpleDispatch_2p_adjphase =+ simpleDispatch (dpRootFeatFailure >--> dpToResults)+ dpToAgenda++simpleDispatch_1p :: SimpleDispatchFilter+simpleDispatch_1p =+ simpleDispatch (dpRootFeatFailure >--> dpTbFailure >--> dpToResults)+ dpToAgenda++simpleDispatch :: SimpleDispatchFilter -> SimpleDispatchFilter -> SimpleDispatchFilter+simpleDispatch resFilter nonResFilter item =+ do inputsem <- gets tsem+ let synComplete x = siInitial x && closed x && adjdone x+ semComplete x = inputsem == siSemantics x+ isResult x = synComplete x && semComplete x+ condFilter isResult resFilter nonResFilter item++dpAux, dpToAgenda :: SimpleDispatchFilter+dpTbFailure, dpToResults :: SimpleDispatchFilter+dpToTrash :: String -> SimpleDispatchFilter++dpToAgenda x = addToAgenda x >> return Filtered+dpToResults x = addToResults x >> return Filtered+dpToTrash m x = addToTrash x m >> return Filtered++dpAux item =+ if closedAux item+ then addToAuxAgenda item >> return Filtered+ else return (NotFiltered item)++{-+-- | Dispatches to the trash and returns Nothing if there is a tree+-- size limit in effect and the item is over that limit. The+-- tree size limit is used in 'IgnoreSemantics' mode.+dpTreeLimit item =+ do config <- gets genconfig+ case maxTrees config of+ Nothing -> return $ Just item+ Just lim -> if (length.snd.siDerivation) item > lim+ then do addToTrash item (ts_overnumTrees lim)+ return Nothing+ else return $ Just item+ where ts_overnumTrees l = "Over derivation size of " ++ (show l)+-}++dpTbNaFailure :: SimpleDispatchFilter+dpTbNaFailure item =+ case tbUnifyNaNodes (siNodes item) of+ Nothing -> dpToTrash ("top-bottom unification failure in NA nodes") item+ Just (ns2,s) -> return . NotFiltered . replace s $ item { siNodes = ns2 }++-- | This is only used for the one-phase algorithm+dpTbFailure item =+ return (if tbUnifyTree item then NotFiltered item else Filtered)++-- | If the item (ostensibly a result) does not have the correct root+-- category, return Nothing; otherwise return Just item+dpRootFeatFailure :: SimpleDispatchFilter+dpRootFeatFailure item =+ do config <- gets genconfig+ let rootFeat = getListFlagP RootFeatureFlg config+ (TagSite _ top _ _) = siRoot item+ case unifyFeat rootFeat top of+ Nothing ->+ dpToTrash (ts_rootFeatureMismatch rootFeat) item+ Just (_, s) ->+ return . NotFiltered $ replace s item++-- --------------------------------------------------------------------+-- Top and bottom unification+-- --------------------------------------------------------------------++tbUnifyNaNodes :: [GNode GeniVal] -> Maybe ([GNode GeniVal], Subst)+tbUnifyNaNodes [] = Just ([], Map.empty)+tbUnifyNaNodes (n:ns) =+ if gaconstr n+ then do (ud, sub) <- unifyFeat (gup n) (gdown n)+ let n2 = n { gup = ud, gdown = [] }+ (ns2, sub2) <- tbUnifyNaNodes (replace sub ns)+ return (n2:ns2, sub `appendSubst` sub2)+ else first (n:) `fmap` tbUnifyNaNodes ns++type TbEither = Either Text Subst+tbUnifyTree :: SimpleItem -> Bool+tbUnifyTree item = {-# SCC "tbUnifyTree" #-}+ case foldl' tbUnifyNode (Right Map.empty) pending of+ Left _ -> False+ Right _ -> True+ where+ pending = map (toTagSite . lookupOrBug "tbUnifyTree" item) (siPendingTb item)++tbUnifyNode :: TbEither -> TagSite -> TbEither+tbUnifyNode (Right pending) rawSite =+ -- apply pending substitutions+ case replace pending rawSite of+ (TagSite name up down _) ->+ -- check top/bottom unification on this node+ case unifyFeat up down of+ -- stop all future iterations+ Nothing -> Left name+ -- apply any new substutions to the whole tree+ Just (_,sb) -> Right (appendSubst pending sb)++-- if earlier we had a failure, don't even bother+tbUnifyNode (Left n) _ = Left n++-- --------------------------------------------------------------------+-- Unpacking the results+-- --------------------------------------------------------------------++unpackResults :: [SimpleItem] -> [B.Output]+unpackResults = concatMap unpackResult++--Change, instead of returning the features of the parent node for every leaf, return:+-- -the features of the parent node when the leaf doesn't have features (top and bottom feature structure empty)+-- -the features of the node in case it has (in this case return the unification of top and bottom features).+unpackResult :: SimpleItem -> [B.Output]+unpackResult item =+ let look = lookupOrBug "unpackResult" item+ toUninflectedDisjunction (pt,t) =+ --B.UninflectedDisjunction (getLexeme (look t)) (gup (look pt)) + B.UninflectedDisjunction (getLexeme (look t))+ (gup . look $ if emptyFeatureStr (look t) then pt else t)++ derivation = siDerivation item+ paths = automatonPaths . listToSentenceAut . map toUninflectedDisjunction . preTerminals . siDerived $ item+ in map (\p -> (siId item, p, derivation)) paths++emptyFeatureStr :: GNode GeniVal -> Bool+emptyFeatureStr n= null (gdown n) && null (gup n)++-- Sentence automata++listToSentenceAut :: [ B.UninflectedDisjunction ] -> B.SentenceAut+listToSentenceAut nodes =+ let theStart = 0+ theEnd = length nodes - 1+ theStates = [theStart..theEnd]+ --+ emptyAut = NFA+ { startSt = theStart+ , isFinalSt = Nothing+ , finalStList = [theEnd]+ , states = [theStates]+ , transitions = Map.empty }+ -- create a transition for each lexeme in the node to the+ -- next state...+ helper :: (Int, B.UninflectedDisjunction) -> B.SentenceAut -> B.SentenceAut+ helper (current, B.UninflectedDisjunction lemmas features) aut =+ foldl' addT aut lemmas+ where+ addT a t = addTrans a current (Just (LemmaPlus t features)) next+ next = current + 1+ --+ in foldr helper emptyAut (zip theStates nodes)++-- --------------------------------------------------------------------+-- Partial results+-- --------------------------------------------------------------------++partialResults :: SimpleStatus -> [SimpleItem]+partialResults st = unfoldr getNext 0+ where+ inputsem = tsem st+ trash = theTrash st+ trashC = sortBy (comparing $ negate . fst) $+ map (\t -> (coverage inputsem t, t)) trash+ getNext sem = case getItems sem of+ [] -> Nothing+ (it:_) -> Just (it, siSemantics it .|. sem)+ getItems sem = [ i | (_,i) <- trashC, siSemantics i .&. sem == 0 ]++coverage :: BitVector -> SimpleItem -> Int+coverage sem it = countBits (sem .&. siSemantics it)++countBits :: Bits a => a -> Int+countBits 0 = 0+countBits bs = if testBit bs 0 then 1 + next else next+ where next = countBits (shiftR bs 1)++-- --------------------------------------------------------------------+-- Performance+-- --------------------------------------------------------------------++{-+instance NFData SimpleItem where+ rnf (SimpleItem x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13+ ) = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` rnf x4 `seq` rnf x5 `seq` rnf x6+ `seq` rnf x7 `seq` rnf x8 `seq` rnf x9 `seq` rnf x10 `seq` rnf x11+ `seq` rnf x11 `seq` rnf x12 `seq` rnf x13+ `seq` rnf x14+-}
− src/NLP/GenI/Simple/SimpleBuilder.lhs
@@ -1,1225 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.--\chapter{SimpleBuilder}-\label{cha:SimpleBuilder}--A SimpleBuilder is a Builder which constructs derived trees using a-simple agenda control mechanism and two-phase realisation (substitution-before adjunction). There is no packing strategy whatsoever; each chart-item is a derived tree.--\begin{code}-{-# OPTIONS_GHC -fglasgow-exts -fno-warn-orphans #-}-{-# LANGUAGE LiberalTypeSynonyms, TemplateHaskell #-}-module NLP.GenI.Simple.SimpleBuilder (- -- Types- Agenda, AuxAgenda, Chart, SimpleStatus, SimpleState,- SimpleItem(..),-- -- From SimpleStatus- simpleBuilder_1p, simpleBuilder_2p, simpleBuilder,- theAgenda, theHoldingPen, theChart, theResults,- initSimpleBuilder,- addToAgenda, addToChart,- genconfig,- SimpleGuiItem(..),- theTrash, step,-- unpackResult,- )-where-\end{code}---\ignore{-\begin{code}-import Control.Arrow ( second )-import Control.Monad (when, unless, liftM2)-import Control.Monad.State.Strict- (get, put, modify, gets, runState, execStateT)--import Data.List (partition, delete, foldl')-import Data.Maybe (isJust, isNothing, mapMaybe)-import Data.Ord (comparing)-import Data.Bits-import qualified Data.Map as Map-import Data.Tree--import Data.Generics ( Data )-import Data.Generics.PlateDirect--import NLP.GenI.Statistics (Statistics)--import NLP.GenI.Automaton ( automatonPaths, NFA(..), addTrans )-import NLP.GenI.Btypes- ( Ptype(Initial)- , GeniVal- , replace, DescendGeniVal(..)- , GNode(..), NodeName- , root, foot- , plugTree, spliceTree- , unifyFeat, Flist, Subst, mergeSubst- )-import NLP.GenI.Builder (- incrCounter, num_iterations, num_comparisons, chart_size,- SemBitMap, defineSemanticBits, semToBitVector, bitVectorToSem,- DispatchFilter, (>-->), condFilter, nullFilter,- semToIafMap, IafAble(..), IafMap, fromUniConst, getIdx,- recalculateAccesibility, iafBadSem, ts_iafFailure,- LemmaPlus(..),- )-import qualified NLP.GenI.Builder as B--import NLP.GenI.Tags (TagElem, TagSite(..),- tagLeaves, tidnum,- ttree, ttype, tsemantics,- detectSites,- TagDerivation, DerivationStep(..),- ts_rootFeatureMismatch,- )-import NLP.GenI.Configuration-import NLP.GenI.General- ( BitVector, mapMaybeM, mapTree', geniBug, preTerminals, )--import NLP.GenI.Btypes ( GType(Other), sortSem, Sem, gnnameIs )-import NLP.GenI.General ( repList, )-import NLP.GenI.Tags ( idname,- ts_synIncomplete, ts_semIncomplete, ts_tbUnificationFailure,- )--import Data.List ( sortBy, unfoldr )-\end{code}-}--% ---------------------------------------------------------------------\section{The Builder interface}-% ----------------------------------------------------------------------Here is our implementation of Builder.--\begin{code}-type SimpleBuilder = B.Builder SimpleStatus SimpleItem Params-simpleBuilder_2p, simpleBuilder_1p :: SimpleBuilder-simpleBuilder_2p = simpleBuilder True-simpleBuilder_1p = simpleBuilder False--simpleBuilder :: Bool -> SimpleBuilder-simpleBuilder twophase = B.Builder- { B.init = initSimpleBuilder twophase- , B.step = if twophase then generateStep_2p else generateStep_1p- , B.stepAll = B.defaultStepAll (simpleBuilder twophase)- , B.finished = \s -> (null.theAgenda) s && (not twophase || isAdjunctionPhase (step s))- , B.unpack = unpackResults.theResults- , B.partial = unpackResults.partialResults- }-\end{code}--% ---------------------------------------------------------------------\section{Key types}-% ----------------------------------------------------------------------\begin{code}-type Agenda = [SimpleItem]-type AuxAgenda = [SimpleItem]-type Chart = [SimpleItem]-type Trash = [SimpleItem]--data GenerationPhase = SubstitutionPhase- | AdjunctionPhase- deriving (Show)--isAdjunctionPhase :: GenerationPhase -> Bool-isAdjunctionPhase AdjunctionPhase = True-isAdjunctionPhase _ = False-\end{code}--\subsection{SimpleState and SimpleStatus}--The \fnreflite{SimpleState} is a state monad where the state being-thread through is a \fnreflite{SimpleStatus}. The two are named-deliberately alike to indicate their close relationship.--To prevent confusion, we ought to keep a somewhat consistent naming-scheme across the builders: FooState for the state monad, FooStatus for-the state monad's ``contents'', and FooItem for the chart items-manipulated.--Note the theTrash is not actually essential to the operation of the-generator; it is for pratical debugging of grammars. Instead of-trees dissapearing off the face of the debugger; they go into the-trash where the user can inspect them and try to figure out why they-went wrong.--\begin{code}-type SimpleState a = B.BuilderState SimpleStatus a--data SimpleStatus = S- { theAgenda :: Agenda- , theHoldingPen :: AuxAgenda- , theChart :: Chart- , theTrash :: Trash- , theResults :: [SimpleItem]- , theIafMap :: IafMap -- for index accessibility filtering- , tsem :: BitVector- , step :: GenerationPhase- , gencounter :: Integer- , genconfig :: Params- -- we keep a SemBitMap strictly to help display the semantics- , semBitMap :: SemBitMap- }- deriving Show-\end{code}--\subsubsection{SimpleStatus updaters}--\begin{code}-addToAgenda :: SimpleItem -> SimpleState ()-addToAgenda te =- modify $ \s -> s{theAgenda = te : theAgenda s }--updateAgenda :: Agenda -> SimpleState ()-updateAgenda a =- modify $ \s -> s{theAgenda = a}--addToAuxAgenda :: SimpleItem -> SimpleState ()-addToAuxAgenda te = do- s <- get- -- each new tree gets a unique id... this makes comparisons faster- let counter = gencounter s + 1- te2 = te { siId = counter }- put s{gencounter = counter,- theHoldingPen = te2 : theHoldingPen s }--addToChart :: SimpleItem -> SimpleState ()-addToChart te = do- modify $ \s -> s { theChart = te:theChart s }- incrCounter chart_size 1--addToTrash :: SimpleItem -> String -> SimpleState ()-addToTrash te err = do- disableGui <- gets (hasFlagP DisableGuiFlg . genconfig)- unless disableGui $- modify $ \s -> s { theTrash = te2 : theTrash s }- where- te2 = modifyGuiStuff (\g -> g { siDiagnostic = err:siDiagnostic g }) te--addToResults :: SimpleItem -> SimpleState ()-addToResults te =- modify $ \s -> s { theResults = te : theResults s }-\end{code}--\subsection{SimpleItem}--\begin{code}-data SimpleItem = SimpleItem- { siId :: ChartId- --- , siSubstnodes :: [TagSite]- , siAdjnodes :: [TagSite]- --- , siSemantics :: BitVector- , siPolpaths :: BitVector- -- for generation sans semantics- -- , siAdjlist :: [(String,Integer)] -- (node name, auxiliary tree id)- -- for index accesibility filtering (one-phase only)- , siAccesible :: [ String ] -- it's acc/inacc/undetermined- , siInaccessible :: [ String ] -- that's why you want both- --- -- | actually: a set of pre-terminals and their leaves- , siLeaves :: [(String, B.UninflectedDisjunction)]- , siDerived :: Tree String- , siRoot :: TagSite- , siFoot :: Maybe TagSite- --- , siPendingTb :: [ TagSite ] -- only for one-phase- -- how was this item produced?- , siDerivation :: TagDerivation- -- for the debugger only- , siGuiStuff :: SimpleGuiItem- } deriving (Show)--instance Biplate SimpleItem GeniVal where- biplate (SimpleItem x1 zss zas x2 x3 x4 x5 zls x6 zr zf zp x7 zg) =- plate SimpleItem |- x1- ||+ zss ||+ zas |- x2 |- x3 |- x4 |- x5- ||+ zls |- x6- |+ zr |+ zf ||+ zp |- x7- |+ zg--instance Biplate (String, B.UninflectedDisjunction) GeniVal where- biplate (s,d) = plate (,) |- s |+ d--instance DescendGeniVal (String, B.UninflectedDisjunction) where- descendGeniVal m (s,d) = (s, descendGeniVal m d)---- | Things whose only use is within the graphical debugger-data SimpleGuiItem = SimpleGuiItem- { siHighlight :: [String] -- ^ nodes to highlight- , siNodes :: [GNode] -- ^ actually a set- -- if there are things wrong with this item, what?- , siDiagnostic :: [String]- , siFullSem :: Sem- , siIdname :: String- } deriving (Show, Data, Typeable)--instance Biplate SimpleGuiItem GeniVal where- biplate (SimpleGuiItem x1 zns x2 zsem x3) =- plate SimpleGuiItem |- x1- ||+ zns |- x2- ||+ zsem |- x3--emptySimpleGuiItem :: SimpleGuiItem-emptySimpleGuiItem = SimpleGuiItem [] [] [] [] ""--modifyGuiStuff :: (SimpleGuiItem -> SimpleGuiItem) -> SimpleItem -> SimpleItem-modifyGuiStuff fn i = i { siGuiStuff = fn . siGuiStuff $ i }--type ChartId = Integer--instance DescendGeniVal SimpleItem where- descendGeniVal s i = s `seq` i `seq`- i { siSubstnodes = descendGeniVal s (siSubstnodes i)- , siAdjnodes = descendGeniVal s (siAdjnodes i)- , siLeaves = descendGeniVal s (siLeaves i)- , siRoot = descendGeniVal s (siRoot i)- , siFoot = descendGeniVal s (siFoot i)- , siPendingTb = descendGeniVal s (siPendingTb i)- , siGuiStuff = descendGeniVal s (siGuiStuff i)- }--instance DescendGeniVal SimpleGuiItem where- descendGeniVal s i = i { siNodes = descendGeniVal s (siNodes i) }-\end{code}--\begin{code}-{-# INLINE closedAux #-}---- | True if the chart item has no open substitution nodes-closed :: SimpleItem -> Bool-closed = null.siSubstnodes---- | True if the chart item is an auxiliary tree-aux :: SimpleItem -> Bool-aux = isJust . siFoot---- | True if both 'closed' and 'aux' are True-closedAux :: SimpleItem -> Bool-closedAux x = aux x && closed x--adjdone :: SimpleItem -> Bool-adjdone = null.siAdjnodes--siInitial :: SimpleItem -> Bool-siInitial = isNothing . siFoot-\end{code}--% ---------------------------------------------------------------------\section{Initialisation}-% ----------------------------------------------------------------------\begin{code}--- | Creates an initial SimpleStatus.-initSimpleBuilder :: Bool -> B.Input -> Params -> (SimpleStatus, Statistics)-initSimpleBuilder twophase input config =- let disableGui = hasFlagP DisableGuiFlg config- cands = map (initSimpleItem disableGui bmap) $ B.inCands input- (sem,_,_) = B.inSemInput input- bmap = defineSemanticBits sem- -- FIXME: I don't know if this matters for one-phase- -- because of on-the-fly tb unification (in 2p), we- -- need an initial tb step that only addresses the- -- nodes with null adjunction constraints- simpleDp = if twophase then simpleDispatch_2p- else simpleDispatch_1p (hasOpt Iaf config)- initialDp = dpTbFailure >--> simpleDp- --- initS = S{ theAgenda = []- , theHoldingPen = []- , theChart = []- , theTrash = []- , theResults = []- , semBitMap = bmap- , tsem = semToBitVector bmap sem- , theIafMap = semToIafMap sem- , step = SubstitutionPhase- , gencounter = toInteger $ length cands- , genconfig = config }- --- in B.unlessEmptySem input config $- runState (execStateT (mapM initialDp cands) initS) (B.initStats config)---initSimpleItem :: Bool -- ^ disable gui- -> SemBitMap -> (TagElem, BitVector) -> SimpleItem-initSimpleItem disableGui bmap (teRaw,pp) =- let (te,tlite) = renameNodesWithTidnum teRaw in- case detectSites (ttree te) of- (snodes,anodes,nullAdjNodes) -> setIaf $ SimpleItem- { siId = tidnum te- , siSemantics = semToBitVector bmap (tsemantics te)- , siSubstnodes = snodes- , siAdjnodes = anodes- , siPolpaths = pp- -- for index accesibility filtering- , siAccesible = [] -- see below- , siInaccessible = []- -- for generation sans semantics- -- , siAdjlist = []- , siLeaves = map (second (uncurry B.UninflectedDisjunction)) $ tagLeaves te- , siDerived = tlite- , siRoot = ncopy.root $ theTree- , siFoot = if ttype te == Initial then Nothing- else Just . ncopy.foot $ theTree- , siDerivation = []- -- note: see comment in initSimpleBuilder re: tb unification- , siPendingTb = nullAdjNodes- --- , siGuiStuff = if disableGui then emptySimpleGuiItem else initSimpleGuiItem te- }- where setIaf i = i { siAccesible = iafNewAcc i }- theTree = ttree te--initSimpleGuiItem :: TagElem -> SimpleGuiItem-initSimpleGuiItem te = SimpleGuiItem- { siHighlight = []- , siNodes = flatten.ttree $ te- , siDiagnostic = []- , siFullSem = tsemantics te- , siIdname = idname te }--renameNodesWithTidnum :: TagElem -> (TagElem, Tree NodeName)-renameNodesWithTidnum te =- ( te { ttree = mapTree' renameNode theTree }- , mapTree' newName theTree )- where theTree = ttree te- renameNode n = n { gnname = newName n }- newName n = gnname n ++ "-" ++ tidstr- tidstr = show . tidnum $ te-\end{code}--% ---------------------------------------------------------------------\section{Generate}-% ----------------------------------------------------------------------\subsection{One-phase generation}--This is a standard chart-and-agenda mechanism, where each iteration-consists of picking an item off the agenda and combining it with-elements from the chart.--\begin{code}-generateStep_1p :: SimpleState ()-generateStep_1p =- do isDone <- gets (null.theAgenda)- iaf <- gets (hasOpt Iaf .genconfig)- let dispatch = mapM (simpleDispatch_1p iaf)- if isDone- then return ()- else do incrCounter num_iterations 1- given <- selectGiven- -- do both substitution and adjunction- applySubstitution1p given >>= dispatch- passiveAdjunction1p given >>= dispatch- activeAdjunction1p given >>= dispatch- sansAdjunction1p given >>= dispatch- -- determine which of the res should go in the agenda- -- (monadic state) and which should go in the result (res')- addToChart given-\end{code}--\subsection{Two-phase generation}--Following \cite{carroll1999ecg}, we could also separate realisation into-two distinct phases. This requires that we maintain two seperate-agendas and process them sequentially, one loop after the other. See-\fnref{switchToAux} for details.--\begin{itemize}-\item If both Agenda and AuxAgenda are empty then there is nothing to do,- otherwise, if Agenda is empty then we switch to the application of the- Adjunction rule.-\item After the rule is applied we classify solutions into those that are complete- and cover the semantics and those that don't. The first ones are returned- and added to the result, while the others are sent back to Agenda.-\item Notice that if we are applying the Substitution rule then the- current agenda item is added to the chart, otherwise it is deleted.-\end{itemize}--\begin{code}-generateStep_2p :: SimpleState ()-generateStep_2p = do- nir <- gets (null.theAgenda)- curStep <- gets step- case curStep of- SubstitutionPhase -> if nir then switchToAux else generateStep_2p_sub- AdjunctionPhase -> if nir then return () else generateStep_2p_adj--generateStep_2p_sub :: SimpleState ()-generateStep_2p_sub =- do incrCounter num_iterations 1- -- choose an item from the agenda- given <- selectGiven- res <- applySubstitution given- mapM_ simpleDispatch_2p res- -- put the given into the chart untouched- addToChart given--generateStep_2p_adj :: SimpleState ()-generateStep_2p_adj =- do incrCounter num_iterations 1- -- choose an item from the agenda- given <- selectGiven- res <- liftM2 (++) (applyAdjunction2p given) (sansAdjunction2p given)- mapM_ simpleDispatch_2p_adjphase res- when (adjdone given) $ trashIt given-\end{code}--\subsection{Helpers for the generateSteps}--\begin{code}-trashIt :: SimpleItem -> SimpleState ()-trashIt item =- do disableGui <- gets (hasFlagP DisableGuiFlg . genconfig)- unless disableGui $ do- s <- get- let bmap = semBitMap s- itemSem = siSemantics item- inputSem = tsem s- reason = if inputSem == itemSem- then "unknown reason!"- else ts_semIncomplete $ bitVectorToSem bmap $ inputSem `xor` itemSem- addToTrash item reason---- | Arbitrarily selects and removes an element from the agenda and--- returns it.-selectGiven :: SimpleState SimpleItem-selectGiven = do- agenda <- gets theAgenda- case agenda of- [] -> geniBug "null agenda in selectGiven"- (a:atail) -> updateAgenda atail >> return a-\end{code}--\subsection{Switching phases}--After the substitution and na-constraint phases are complete, we switch to the-final adjunction phase. We do this by deleting junk from the agenda-(particularly, trees with open substitution sites remaining), transfering trees-from the holding pen to the chart and setting the phase to AdjunctionPhase--\begin{code}-switchToAux :: SimpleState ()-switchToAux = do- st <- get- let oldAuxTrees = theHoldingPen st- config = genconfig st- -- You might be wondering why we ignore the auxiliary trees in the- -- chart; this is because all the syntactically complete auxiliary- -- trees have already been filtered away by calls to classifyNew- initialT = filter siInitial (theChart st)- (compT1, incompT1) = partition (null.siSubstnodes) initialT- --- (auxTrees, compT2) =- if hasOpt EarlyNa config- then ( mapMaybe (detectNa oldAuxTrees) oldAuxTrees- , mapMaybe (detectNa auxTrees) compT1 )- else ( oldAuxTrees, compT1 )- --- (compT3, incompT3) =- if hasOpt SemFiltered config- then semfilter (tsem st) auxTrees compT2- else (compT2, [])- --- compT = compT3- -- the root cat filter by Claire- put st{ theAgenda = []- , theHoldingPen = []- , theChart = auxTrees- , step = AdjunctionPhase }- mapM_ simpleDispatch_2p_adjphase compT- -- toss the syntactically incomplete stuff in the trash- mapM_ (\t -> addToTrash t ts_synIncomplete) incompT1- mapM_ (\t -> addToTrash t "sem-filtered") incompT3-\end{code}--\subsubsection{SemFilter Optimisation}-\label{sec:semfilter}--The purpose of the semantic filter optimisation is to take full-advantage of Carroll's delayed adjunction. Consider the semantics-\semexpr{def(m), poor(m), brokenhearted(m), man(m), def(w), woman(w),-beautiful(w), heartless(w), rejects(w,m)}. At the switchToAux step, we-are left with the initial trees \natlang{man}, \natlang{woman}, \natlang{the- woman rejects the man}.--It would be nice to filter out the structures \natlang{man} and \natlang{woman}-since we know that they are not going to be semantically complete even with-adjunction. More precisely, on the switch to adjunction, we do the following:--\begin{itemize}-\item Take the union of the semantics of all auxiliary trees; which- we call $\phi^*$-\item Delete any initial tree with semantics $\phi^s$ such that- $\phi^s \cup \phi^*$ is not the target semantics-\end{itemize}--In other words, we delete all initial trees that cannot produce a semantically-complete result even with the help of auxiliary trees.--FIXME: comment 2006-04-18: sem filter each polarity path separately (this is-more aggressive; it gives us much more filtering)--\begin{code}-semfilter :: BitVector -> [SimpleItem] -> [SimpleItem] -> ([SimpleItem], [SimpleItem])-semfilter inputsem auxs initial =- let auxsem x = foldl' (.|.) 0 [ siSemantics a | a <- auxs, siPolpaths a .&. siPolpaths x /= 0 ]- -- lite, here, means sans auxiliary semantics- notjunk x = (siSemantics x) .&. inputsemLite == inputsemLite- where inputsemLite = inputsem `xor` (auxsem x)- -- note that we can't just compare against siSemantics because- -- that would exclude trees that have stuff in the aux semantics- -- which would be overzealous- in partition notjunk initial-\end{code}--% ---------------------------------------------------------------------\section{Operations}-% ----------------------------------------------------------------------We implement the two TAG operations, substitution and adjunction, below.-These are the only two operations we have, because we're working with a-very simple builder that constructs derived trees.--% ---------------------------------------------------------------------\subsection{Substitution}-\label{sec:substitution}-% ----------------------------------------------------------------------\paragraph{applySubstitution} Given a SimpleItem it returns the list of all-possible substitutions between it and the elements in Chart--\begin{code}-applySubstitution :: SimpleItem -> SimpleState ([SimpleItem])-applySubstitution item =- do gr <- lookupChart item- active <- mapM (\x -> iapplySubst True item x) gr- passive <- mapM (\x -> iapplySubst True x item) gr- let res = concat $ active ++ passive- incrCounter num_comparisons (2 * (length gr))- return res--applySubstitution1p :: SimpleItem -> SimpleState ([SimpleItem])-applySubstitution1p item =- do gr <- lookupChart item- active <- if adjdone item then return []- else mapM (\x -> iapplySubst False item x) gr- passive <- mapM (\x -> iapplySubst False x item) $ filter adjdone gr- let res = concat $ active ++ passive- incrCounter num_comparisons (2 * (length gr))- return res---- | Note: returns ONE possible substitution (the head node)--- of the first in the second. As all substitutions nodes should--- be substituted we force substitution in order.-iapplySubst :: Bool -> SimpleItem -> SimpleItem -> SimpleState [SimpleItem]-iapplySubst twophase item1 item2 | siInitial item1 && closed item1 = {-# SCC "applySubstitution" #-}- case siSubstnodes item2 of- [] -> return []- ((TagSite n fu fd nOrigin) : stail) ->- let doIt =- do -- Maybe monad- let r@(TagSite rn ru rd rOrigin) = siRoot item1- (newU, subst1) <- unifyFeat ru fu- (newD, subst2) <- unifyFeat (replace subst1 rd)- (replace subst1 fd)- let subst = mergeSubst subst1 subst2- nr = TagSite rn newU newD rOrigin- adj1 = nr : (delete r $ siAdjnodes item1)- adj2 = siAdjnodes item2- item1g = item1 { siGuiStuff = g2 }- where g2 = g { siNodes = repList (gnnameIs rn) newRoot (siNodes g) }- g = siGuiStuff item1- -- gui stuff- newRoot g = g { gup = newU, gdown = newD, gtype = Other }- let pending = if twophase then []- else nr : (siPendingTb item1 ++ siPendingTb item2)- return $! replace subst $ combineSimpleItems [rn] item1g $- item2 { siSubstnodes = stail ++ (siSubstnodes item1)- , siAdjnodes = adj2 ++ adj1- , siDerived = plugTree (siDerived item1) n (siDerived item2)- , siDerivation = addToDerivation 's' (item1g,rOrigin) (item2,nOrigin,n)- , siLeaves = (siLeaves item1) ++ (siLeaves item2)- , siPendingTb = pending- }- in case doIt of- Nothing -> return []- Just x -> do incrCounter "substitutions" 1- return [x]-iapplySubst _ _ _ = return []-\end{code}--% ---------------------------------------------------------------------\subsection{Adjunction}-\label{sec:adjunction}-\label{sec:ordered_adjunction}-\label{sec:foot_constraint}-% -----------------------------------------------------------------\paragraph{applyAdjunction2p} Given a SimpleItem, it returns the list of all-possible adjunctions between it and the elements in Chart.-The Chart contains Auxiliars, while SimpleItem is an Initial--Note: as of 13 april 2005 - only uses ordered adjunction as described in-\cite{kow04a}-\begin{code}-applyAdjunction2p :: SimpleItem -> SimpleState ([SimpleItem])-applyAdjunction2p item = {-# SCC "applyAdjunction2p" #-}- do gr <-lookupChart item- incrCounter num_comparisons (length gr)- mapMaybeM (\a -> tryAdj True a item) gr--passiveAdjunction1p :: SimpleItem -> SimpleState [SimpleItem]-passiveAdjunction1p item | closed item && siInitial item =- do gr <- lookupChart item- mapMaybeM (\a -> tryAdj False a item) $ filter validAux gr-passiveAdjunction1p _ = return []--activeAdjunction1p :: SimpleItem -> SimpleState [SimpleItem]-activeAdjunction1p item | validAux item =- do gr <- lookupChart item- mapMaybeM (\p -> tryAdj False item p) $ filter (\x -> siInitial x && closed x) gr-activeAdjunction1p _ = return []--validAux :: SimpleItem -> Bool-validAux t = closedAux t && adjdone t--tryAdj :: Bool -> SimpleItem -> SimpleItem -> SimpleState (Maybe SimpleItem)-tryAdj twophase aItem pItem =- do case iapplyAdjNode twophase aItem pItem of- Just x -> do incrCounter "adjunctions" 1- return $ Just x- Nothing -> return Nothing-\end{code}--Note that in the one-phase variant of non-adjunction, we can't do top/bot-unification on the fly, because afaik we can't tell that a node will never-be revisited. One example of this is if you try to adjoin into the root--\begin{code}--- | Ignore the next adjunction node-sansAdjunction1p, sansAdjunction2p :: SimpleItem -> SimpleState [SimpleItem]-sansAdjunction1p item | closed item =- case siAdjnodes item of- [] -> return []- (ahead : atail) ->- return $ [item { siAdjnodes = atail- , siPendingTb = ahead : (siPendingTb item) } ]-sansAdjunction1p _ = return []---- | Ignore the next adjunction node-sansAdjunction2p item | closed item =- case siAdjnodes item of- [] -> return []- (TagSite gn t b o: atail) -> do- -- do top/bottom unification on the node- case unifyFeat t b of- Nothing ->- do addToTrash (modifyGuiStuff (\g -> g { siHighlight = [gn] }) item)- ts_tbUnificationFailure- return []- Just (tb,s) ->- let item1 = if isRootOf item gn- then item { siRoot = TagSite gn tb [] o }- else item- item2 = modifyGuiStuff (constrainAdj gn tb) item1- in return $! [replace s $! item2 { siAdjnodes = atail }]-sansAdjunction2p _ = return []-\end{code}--The main work for adjunction is done in the helper function below-(see also figure \ref{fig:adjunction}).-Auxiliary tree \texttt{te1} has a root node \texttt{r} and a foot-node \texttt{f}. Main tree \texttt{te2} has an adjunction site \texttt{an}.-The resulting tree \texttt{res} is a result of splicing \texttt{te1} into-\texttt{te2}. We replace \texttt{s} with the nodes \texttt{anr} and-\texttt{anf} (which are the results of unifying \texttt{an} with \texttt{r}- and \texttt{f} respectively).--\begin{figure}-\begin{center}-\includegraphics[scale=0.5]{images/adjunction.pdf}-\label{fig:adjunction}-\caption{iapplyAdjNode}-\end{center}-\end{figure}--In addition to the trees proper, we have to consider that each tree has-a list with a copy of its adjunction sites. The adjunction list of the-result (\texttt{adjnodes res}) should then contain \texttt{adjnodes te1}-and \texttt{adjnodes te2}, but replacing \texttt{r} and \texttt{an}-with \texttt{anr}.--\begin{code}-iapplyAdjNode :: Bool -> SimpleItem -> SimpleItem -> Maybe SimpleItem-iapplyAdjNode twophase aItem pItem = {-# SCC "iapplyAdjNode" #-}- case siAdjnodes pItem of- [] -> Nothing- (pSite : pTail) -> do- -- let's go!- (anr, anf, subst12) <- canAdjoin aItem pSite- let r = siRoot aItem- f <- siFoot aItem- let an_name = tsName pSite- -- the new adjunction nodes- auxlite = delete r $ siAdjnodes aItem- newadjnodes = anr : (pTail ++ auxlite)- -- Ugh, this is horrible: this is just to make sure the GUI gets- -- updated accordingly. The code used to be a lot simpler, but- -- I started trying to move stuff out of the way in the interests- -- of efficiency, and to pack as much gui-related stuff as possible- -- into a single tuple.- aItem2 = aItem { siGuiStuff = fixNodes $ siGuiStuff aItem }- where fixNodes g = g { siNodes = map (setSites anr) (siNodes g) }- setSites (TagSite n u d _) gn =- if gnname gn == n then gn { gup = u, gdown = d }- else gn- rawCombined =- combineSimpleItems [tsName r, an_name] aItem2 $ pItem- { siAdjnodes = newadjnodes- , siLeaves = siLeaves aItem ++ siLeaves pItem- , siDerived = spliceTree (tsName f) (siDerived aItem) an_name (siDerived pItem)- , siDerivation = addToDerivation 'a' (aItem,tsOrigin r) (pItem,tsOrigin pSite,an_name)- -- , siAdjlist = (n, (tidnum te1)):(siAdjlist item2)- -- if we adjoin into the root, the new root is that of the aux- -- tree (affects 1p only)- , siRoot = if isRootOf pItem an_name then r else siRoot pItem- , siPendingTb =- if twophase then []- else anf : (siPendingTb pItem) ++ (siPendingTb aItem)- }- -- one phase = postpone tb unification- -- two phase = do tb unification on the fly- finalRes1p = return $ replace subst12 rawCombined- finalRes2p =- do -- tb on the former foot- tbRes <- unifyFeat (tsUp anf) (tsDown anf)- let (anf_tb, subst3) = tbRes- myRes = modifyGuiStuff (constrainAdj an_name anf_tb) res'- -- apply the substitutions- res' = replace (mergeSubst subst12 subst3) rawCombined- return myRes- -- ---------------- if twophase then finalRes2p else finalRes1p---- Note that we do not propagate variable substitutions in the nodes we return-canAdjoin :: SimpleItem -> TagSite -> Maybe (TagSite, TagSite, Subst)-canAdjoin aItem pSite = do- -- let's go!- let r = siRoot aItem -- auxiliary tree, eh?- f <- siFoot aItem -- should really be an error if fails- (anr_up', subst1) <- unifyFeat (tsUp r) (tsUp pSite)- (anf_down, subst2) <- unifyFeat (replace subst1 $ tsDown f) (replace subst1 $ tsDown pSite)- let -- combined substitution list and success condition- subst12 = mergeSubst subst1 subst2- anr = replace subst12 $ r { tsUp = anr_up' }- anf = replace subst12 $ pSite { tsDown = anf_down }- return (anr, anf, subst12)-\end{code}--\begin{code}-detectNa :: [SimpleItem] -- ^ aux trees- -> SimpleItem -- ^ me- -> Maybe SimpleItem-detectNa rawAux i = helper (siAdjnodes i) Map.empty []- where- compatAux = filterCompatible i rawAux- helper [] s acc = Just $ replace s $ i { siAdjnodes = acc }- helper (t:ts) s acc =- let hasAdj = any isJust $ map (\a -> canAdjoin a t) compatAux- in case (snd `fmap` unifyFeat (tsUp t) (tsDown t)) of- Just s2 -> if hasAdj- then helper ts s (t : acc)- else helper (replace s2 ts) (mergeSubst s s2) acc- Nothing -> if hasAdj- then helper ts s (t : acc)- else Nothing-\end{code}--% ---------------------------------------------------------------------\subsection{Helper functions for operations}-% ----------------------------------------------------------------------\begin{code}-ncopy :: GNode -> TagSite-ncopy x = TagSite (gnname x) (gup x) (gdown x) (gorigin x)--isRootOf :: SimpleItem -> String -> Bool-isRootOf item n = n == rname- where (TagSite rname _ _ _) = siRoot item---- | Retrieves a list of trees from the chart which could be combined with the given agenda tree.--- The current implementation searches for trees which--- * do not have overlapping semantics with the given--- * are on the some of the same polarity automaton paths as the--- current agenda item-lookupChart :: SimpleItem -> SimpleState [SimpleItem]-lookupChart given = gets (filterCompatible given . theChart)--filterCompatible :: SimpleItem -> [SimpleItem] -> [SimpleItem]-filterCompatible given chart =- [ i | i <- chart- -- should be on the same polarity path (chart sharing)- , (siPolpaths i) .&. gpaths /= 0- -- semantics should not be overlapping- && (siSemantics i .&. gsem ) == 0- ]- where- gpaths = siPolpaths given- gsem = siSemantics given---- | Helper function for when chart operations succeed.-combineSimpleItems :: [NodeName] -- ^ nodes to highlight- -> SimpleItem -> SimpleItem -> SimpleItem-combineSimpleItems hi item1 item2 = {-# SCC "combineSimpleItems" #-}- item2 { siSemantics = siSemantics item1 .|. siSemantics item2- , siPolpaths = siPolpaths item1 .&. siPolpaths item2- , siGuiStuff = combineSimpleGuiItems hi (siGuiStuff item1) (siGuiStuff item2)- }--combineSimpleGuiItems :: [NodeName]- -> SimpleGuiItem -> SimpleGuiItem -> SimpleGuiItem-combineSimpleGuiItems hi item1 item2 =- item2 { siFullSem = sortSem $ siFullSem item1 ++ siFullSem item2- , siNodes = siNodes item1 ++ siNodes item2- , siDiagnostic = siDiagnostic item1 ++ siDiagnostic item2- , siHighlight = hi- }--constrainAdj :: String -> Flist -> SimpleGuiItem -> SimpleGuiItem-constrainAdj gn newT g =- g { siNodes = repList (gnnameIs gn) fixIt (siNodes g) }- where fixIt n = n { gup = newT, gdown = [], gaconstr = True }-\end{code}--\subsubsection{Derivation trees}--We make the simplifying assumption that each chart item is only used once.-This is clearly wrong if we allow for items with an empty semantics, but-since we do not actually allow such a thing, we're ok.--\begin{code}-addToDerivation :: Char- -> (SimpleItem,String)- -> (SimpleItem,String,String)- -> TagDerivation-addToDerivation op (tc,tcOrigin) (tp,tpOrigin,tpSite) =- let hp = siDerivation tp- hc = siDerivation tc- newnode = DerivationStep op tcOrigin tpOrigin tpSite- in newnode:hp++hc-\end{code}----% ---------------------------------------------------------------------\section{Dispatching new results}-% ----------------------------------------------------------------------Dispatching is the process where new chart items are assigned to one of-the trash, agenda, auxiliary agenda or chart. The item could be-modified during dispatch-time; for example, we might do top/bottom-unification on it. See \ref{sec:dispatching} for more details.--\begin{code}-type SimpleDispatchFilter = DispatchFilter SimpleState SimpleItem--simpleDispatch_2p :: SimpleDispatchFilter-simpleDispatch_2p =- simpleDispatch (dpRootFeatFailure >--> dpToResults)- (dpAux >--> dpToAgenda)--simpleDispatch_2p_adjphase :: SimpleDispatchFilter-simpleDispatch_2p_adjphase =- simpleDispatch (dpRootFeatFailure >--> dpToResults)- dpToAgenda--simpleDispatch_1p :: Bool -> SimpleDispatchFilter-simpleDispatch_1p iaf =- simpleDispatch (dpRootFeatFailure >--> dpTbFailure >--> dpToResults)- (maybeDpIaf >--> dpToAgenda)- where maybeDpIaf = if iaf then dpIafFailure else nullFilter--simpleDispatch :: SimpleDispatchFilter -> SimpleDispatchFilter -> SimpleDispatchFilter-simpleDispatch resFilter nonResFilter item =- do inputsem <- gets tsem- let synComplete x = siInitial x && closed x && adjdone x- semComplete x = inputsem == siSemantics x- isResult x = synComplete x && semComplete x- condFilter isResult resFilter nonResFilter item--dpAux, dpToAgenda :: SimpleDispatchFilter-dpTbFailure, dpToResults :: SimpleDispatchFilter-dpToTrash :: String -> SimpleDispatchFilter--dpToAgenda x = addToAgenda x >> return Nothing-dpToResults x = addToResults x >> return Nothing-dpToTrash m x = addToTrash x m >> return Nothing--dpAux item =- if closedAux item- then addToAuxAgenda item >> return Nothing- else return $ Just item--{---- | Dispatches to the trash and returns Nothing if there is a tree--- size limit in effect and the item is over that limit. The--- tree size limit is used in 'IgnoreSemantics' mode.-dpTreeLimit item =- do config <- gets genconfig- case maxTrees config of- Nothing -> return $ Just item- Just lim -> if (length.snd.siDerivation) item > lim- then do addToTrash item (ts_overnumTrees lim)- return Nothing- else return $ Just item- where ts_overnumTrees l = "Over derivation size of " ++ (show l)--}---- | This is only used for the one-phase algorithm-dpTbFailure item =- return $ if tbUnifyTree item then Just item else Nothing---- | If the item (ostensibly a result) does not have the correct root--- category, return Nothing; otherwise return Just item-dpRootFeatFailure :: SimpleDispatchFilter-dpRootFeatFailure item =- do config <- gets genconfig- let rootFeat = getListFlagP RootFeatureFlg config- (TagSite _ top _ _) = siRoot item- case unifyFeat rootFeat top of- Nothing ->- dpToTrash (ts_rootFeatureMismatch rootFeat) item- Just (_, s) ->- return . Just $ replace s item-\end{code}-% ---------------------------------------------------------------------\subsection{Top and bottom unification}-% ----------------------------------------------------------------------\paragraph{tbUnifyTree} unifies the top and bottom feature structures-of each node on each tree. Note: this only determines if it is-possible to do so. Actually returning the results is possible-and even easy-(you'll have to look back into the darcs repository and unpull the- patch from 2006-05-21T15:40:51 ``Remove top/bot unification standalone- code.'')-but since it is only used in the one-phase algorithm and for the-graphical interface, I decided not to bother.--\begin{code}-type TbEither = Either String Subst-tbUnifyTree :: SimpleItem -> Bool-tbUnifyTree item = {-# SCC "tbUnifyTree" #-}- case foldl' tbUnifyNode (Right Map.empty) (siPendingTb item) of- Left _ -> False- Right _ -> True-\end{code}--Our helper function corresponds to the first unification step. It is-meant to be called from a fold. The node argument represents the-current node being explored. The Either argument holds a list of-pending substitutions and a copy of the entire tree.--There are two things going on in here:--\begin{enumerate}-\item check if unification is possible - first we apply the pending- substitutions on the node and then we check if unification- of the top and bottom feature structures of that node- succeeds-\item keep track of the substitutions that need to be performed -- any new substitutions that result from unification are- added to the pending list-\end{enumerate}--Note that we wrap the second argument in a Maybe; this is used to-indicate that if unification suceeds or fails. We also use it to-prevent the function from doing any work if a unification failure-from a previous call has already occured.--Getting this right was a big pain in the butt, so don't go trying to-simplify this over-complicated code unless you know what you're doing.--\begin{code}-tbUnifyNode :: TbEither -> TagSite -> TbEither-tbUnifyNode (Right pending) rawSite =- -- apply pending substitutions- case replace pending rawSite of- (TagSite name up down _) ->- -- check top/bottom unification on this node- case unifyFeat up down of- -- stop all future iterations- Nothing -> Left name- -- apply any new substutions to the whole tree- Just (_,sb) -> Right (mergeSubst pending sb)---- if earlier we had a failure, don't even bother-tbUnifyNode (Left n) _ = Left n-\end{code}--% ---------------------------------------------------------------------\subsection{Index accesibility filtering}-\label{sec:simple:iaf}-% ----------------------------------------------------------------------Note that index accesibility filtering only makes sense for the one-phase-algorithm. See also \ref{sec:iaf} for more details about what this is.--\begin{code}-instance IafAble SimpleItem where- iafAcc = siAccesible- iafInacc = siInaccessible- iafSetAcc a i = i { siAccesible = a }- iafSetInacc a i = i { siInaccessible = a }- iafNewAcc i =- concatMap fromUniConst $- concat [ getIdx up | (TagSite _ up _ _) <- siSubstnodes i ]--dpIafFailure :: SimpleDispatchFilter-dpIafFailure item | aux item = return $ Just item-dpIafFailure itemRaw =- do s <- get- let bmap = semBitMap s- item = recalculateAccesibility itemRaw- badSem = iafBadSem (theIafMap s) bmap (tsem s) siSemantics item- inAcc = iafInacc item- if badSem == 0- then -- can't dispatch, but that's good!- -- (note that we return the item with its iaf criteria updated)- return $ Just item- else dpToTrash (ts_iafFailure inAcc $ bitVectorToSem bmap badSem) item-\end{code}---% ---------------------------------------------------------------------\section{Unpacking the results}-% ----------------------------------------------------------------------Unpacking the results consists of converting each result into a sentence-automaton (to take care of atomic disjunction) and reading the paths of-each automaton.--\begin{code}-unpackResults :: [SimpleItem] -> [B.Output]-unpackResults = concatMap unpackResult--unpackResult :: SimpleItem -> [B.Output]-unpackResult item =- let leafMap :: Map.Map String B.UninflectedDisjunction- leafMap = Map.fromList . siLeaves $ item- lookupOrBug :: NodeName -> B.UninflectedDisjunction- lookupOrBug k = case Map.lookup k leafMap of- Nothing -> geniBug $ "unpackResult : could not find node " ++ k- Just w -> w- derivation = siDerivation item- paths = automatonPaths . listToSentenceAut $- [ lookupOrBug k | (k,_) <- (preTerminals . siDerived) item ]- in zip paths (repeat derivation)-\end{code}--\subsection{Sentence automata}--\fnlabel{listToSentenceAut} converts a list of GNodes into a sentence-automaton. It's a actually pretty stupid conversion in fact. We pretty-much make a straight path through the automaton, with the only-cleverness being that we provide a different transition for each-atomic disjunction.--\begin{code}-listToSentenceAut :: [ B.UninflectedDisjunction ] -> B.SentenceAut-listToSentenceAut nodes =- let theStart = 0- theEnd = length nodes - 1- theStates = [theStart..theEnd]- --- emptyAut = NFA- { startSt = theStart- , isFinalSt = Nothing- , finalStList = [theEnd]- , states = [theStates]- , transitions = Map.empty }- -- create a transition for each lexeme in the node to the- -- next state...- helper :: (Int, B.UninflectedDisjunction) -> B.SentenceAut -> B.SentenceAut- helper (current, B.UninflectedDisjunction lemmas features) aut =- foldl' addT aut lemmas- where- addT a t = addTrans a current (Just (LemmaPlus t features)) next- next = current + 1- --- in foldr helper emptyAut (zip theStates nodes)-\end{code}--% ---------------------------------------------------------------------\section{Partial results}-% ----------------------------------------------------------------------The user may ask for partial results when realisation fails. We implement this-using a greedy, full-commitment algorithm. Find the discarded result that-matches the largest part of the semantics and output that fragment. If there-are parts of the input semantics not covered by that fragment, search for the-largest chunk that covers the missing semantics. Recurse until there are no-more eligible items.--\begin{code}-partialResults :: SimpleStatus -> [SimpleItem]-partialResults st = unfoldr getNext 0- where- inputsem = tsem st- trash = theTrash st- trashC = sortBy (comparing $ negate . fst) $- map (\t -> (coverage inputsem t, t)) trash- getNext sem = case getItems sem of- [] -> Nothing- (it:_) -> Just (it, siSemantics it .|. sem)- getItems sem = [ i | (_,i) <- trashC, siSemantics i .&. sem == 0 ]--coverage :: BitVector -> SimpleItem -> Int-coverage sem it = countBits (sem .&. siSemantics it)--countBits :: Bits a => a -> Int-countBits 0 = 0-countBits bs = if testBit bs 0 then 1 + next else next- where next = countBits (shiftR bs 1)-\end{code}--% ---------------------------------------------------------------------% Performance-% ----------------------------------------------------------------------\begin{code}-{--instance NFData SimpleItem where- rnf (SimpleItem x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13- ) = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` rnf x4 `seq` rnf x5 `seq` rnf x6- `seq` rnf x7 `seq` rnf x8 `seq` rnf x9 `seq` rnf x10 `seq` rnf x11- `seq` rnf x11 `seq` rnf x12 `seq` rnf x13- `seq` rnf x14--}-\end{code}-
− src/NLP/GenI/Simple/SimpleGui.lhs
@@ -1,208 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.--\chapter{Simple GUI}--\begin{code}-{-# OPTIONS_GHC -fno-warn-orphans #-}-module NLP.GenI.Simple.SimpleGui where-\end{code}--\ignore{-\begin{code}-import Graphics.UI.WX--import Control.Arrow ( (&&&) )-import Data.IORef-import qualified Data.Map as Map--import NLP.GenI.Statistics (Statistics)--import NLP.GenI.Btypes (GNode(gnname, gup), AvPair(..), emptyGNode, GeniVal(GConst))-import NLP.GenI.Configuration ( Params(..) )-import NLP.GenI.Geni ( ProgStateRef, runGeni, GeniResult )-import NLP.GenI.Graphviz ( GraphvizShow(..), gvNewline, gvUnlines )-import NLP.GenI.GuiHelper- ( messageGui, tagViewerGui,- debuggerPanel, DebuggerItemBar, setGvParams, GvIO, newGvRef, GraphvizGuiSt(..),- viewTagWidgets, XMGDerivation(getSourceTrees),- )-import NLP.GenI.Tags (tsemantics, DerivationStep(dsChild), TagElem(idname, ttree), TagItem(..), emptyTE)-import NLP.GenI.GraphvizShow ( graphvizShowDerivation )--import qualified NLP.GenI.Builder as B-import NLP.GenI.Builder (LemmaPlus(..))-import qualified NLP.GenI.BuilderGui as BG-import NLP.GenI.Polarity-import NLP.GenI.Simple.SimpleBuilder- ( simpleBuilder, SimpleStatus, SimpleItem(..), SimpleGuiItem(..)- , unpackResult- , step, theResults, theAgenda, theHoldingPen, theChart, theTrash)-\end{code}-}--% ---------------------------------------------------------------------\section{Interface}-% ----------------------------------------------------------------------\begin{code}-simpleGui_2p, simpleGui_1p :: BG.BuilderGui-simpleGui_2p = simpleGui True-simpleGui_1p = simpleGui False--simpleGui :: Bool -> BG.BuilderGui-simpleGui twophase = BG.BuilderGui {- BG.resultsPnl = resultsPnl twophase- , BG.debuggerPnl = simpleDebuggerTab twophase }--resultsPnl :: Bool -> ProgStateRef -> Window a -> IO ([GeniResult], Statistics, Layout)-resultsPnl twophase pstRef f =- do (sentences, stats, st) <- runGeni pstRef (simpleBuilder twophase)- (lay, _, _) <- realisationsGui pstRef f (theResults st)- return (sentences, stats, lay)-\end{code}--% ---------------------------------------------------------------------\section{Results}-\label{sec:results_gui}-% ----------------------------------------------------------------------\subsection{Derived Trees}--Browser for derived/derivation trees, except if there are no results, we show a-message box--\begin{code}-realisationsGui :: ProgStateRef -> (Window a) -> [SimpleItem]- -> GvIO () Bool (Maybe SimpleItem)-realisationsGui _ f [] =- do m <- messageGui f "No results found"- g <- newGvRef () False ""- return (m, g, return ())-realisationsGui pstRef f resultsRaw =- do let tip = "result"- itNlabl = map (Just &&& siToSentence) resultsRaw- --- pst <- readIORef pstRef- -- FIXME: have to show the semantics again- tagViewerGui pst f tip "derived" itNlabl-\end{code}--% ---------------------------------------------------------------------\section{Debugger}-\label{sec:simple_debugger_gui}-\label{fn:simpleDebugGui}-% ----------------------------------------------------------------------\begin{code}-simpleDebuggerTab :: Bool -> (Window a) -> Params -> B.Input -> String -> IO Layout-simpleDebuggerTab twophase x1 (pa@x2) =- debuggerPanel (simpleBuilder twophase) False stToGraphviz (simpleItemBar pa)- x1 x2- -stToGraphviz :: SimpleStatus -> [(Maybe SimpleItem, String)]-stToGraphviz st = - let agenda = section "AGENDA" $ theAgenda st- auxAgenda = section "HOLDING" $ theHoldingPen st- trash = section "TRASH" $ theTrash st- chart = section "CHART" $ theChart st- results = section "RESULTS" $ theResults st- --- section n i = hd : (map tlFn i)- where hd = (Nothing, "___" ++ n ++ "___")- tlFn x = (Just x, siToSentence x ++ (showPaths $ siPolpaths x))- showPaths t = " (" ++ showPolPaths t ++ ")"- in concat [ agenda, auxAgenda, chart, trash, results ]--simpleItemBar :: Params -> DebuggerItemBar SimpleStatus Bool SimpleItem-simpleItemBar pa f gvRef updaterFn =- do ib <- panel f []- phaseTxt <- staticText ib [ text := "" ]- detailsChk <- checkBox ib [ text := "Show features"- , checked := False ]- viewTagLay <- viewTagWidgets ib gvRef pa- -- handlers- let onDetailsChk = - do isDetailed <- get detailsChk checked - setGvParams gvRef isDetailed- updaterFn- set detailsChk [ on command := onDetailsChk ]- --- let lay = hfloatCentre . container ib . row 5 $- [ hspace 5- , widget phaseTxt- , hglue- , widget detailsChk- , hglue- , viewTagLay- , hspace 5 ]- let onUpdate =- do status <- gvcore `fmap` readIORef gvRef- set phaseTxt [ text := show (step status) ]- return (lay, onUpdate)-\end{code}--% ---------------------------------------------------------------------\section{Miscellaneous}-% ---------------------------------------------------------------------\begin{code}-instance TagItem SimpleItem where- tgIdName = siIdname.siGuiStuff- tgIdNum = siId- tgSemantics = siFullSem.siGuiStuff--instance XMGDerivation SimpleItem where- -- Note: this is XMG-related stuff- getSourceTrees it = tgIdName it : (map dsChild . siDerivation $ it)-\end{code}--\begin{code}-instance GraphvizShow Bool SimpleItem where- graphvizLabel f c =- graphvizLabel f (toTagElem c) ++ gvNewline ++ (gvUnlines $ siDiagnostic $ siGuiStuff c)-- graphvizParams f c = graphvizParams f (toTagElem c)- graphvizShowAsSubgraph f p it =- let isHiglight n = gnname n `elem` (siHighlight.siGuiStuff) it- info n | isHiglight n = (n, Just "red")- | otherwise = (n, Nothing)- in "\n// ------------------- elementary tree --------------------------\n"- ++ graphvizShowAsSubgraph (f, info) (p ++ "TagElem") (toTagElem it)- ++ "\n// ------------------- derivation tree --------------------------\n"- -- derivation tree is displayed without any decoration- ++ (graphvizShowDerivation . siDerivation $ it)--toTagElem :: SimpleItem -> TagElem-toTagElem si =- emptyTE { idname = tgIdName si- , tsemantics = tgSemantics si- , ttree = fmap lookupOrBug (siDerived si) }- where- nodes = siNodes.siGuiStuff $ si- nodeMap = Map.fromList $ zip (map gnname nodes) nodes- lookupOrBug k = case Map.lookup k nodeMap of- Nothing -> emptyGNode { gup = [ AvPair "cat" (GConst ["error looking up " ++ k]) ] }- Just x -> x-\end{code}--\begin{code}-siToSentence :: SimpleItem -> String-siToSentence si = case unpackResult si of- [] -> siIdname.siGuiStuff $ si- (h:_) -> unwords . map lpLemma . fst $ h-\end{code}
src/NLP/GenI/Statistics.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE FlexibleContexts #-} ---------------------------------------------------- -- -- -- Statistics.hs: --@@ -29,7 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -}-+{-# LANGUAGE FlexibleContexts, RankNTypes #-} module NLP.GenI.Statistics(Statistics, StatisticsState, emptyStats, @@ -46,6 +45,8 @@ import Data.Maybe (mapMaybe) import Text.JSON +import Control.DeepSeq+ ------------------------------------------- -- Statistics are collections of Metrics -- which can be printed out (at regular intervals)@@ -103,3 +104,20 @@ -- not quite showJSON here metricToJSON :: Metric -> (String, JSValue) metricToJSON (IntMetric s i) = (s, showJSON i)++{-!+deriving instance NFData Statistics+deriving instance NFData Metric+!-}+++-- GENERATED START++ +instance NFData Statistics where+ rnf (Stat x1) = rnf x1 `seq` ()++ +instance NFData Metric where+ rnf (IntMetric x1 x2) = rnf x1 `seq` rnf x2 `seq` ()+-- GENERATED STOP
− src/NLP/GenI/SysGeni.hs
@@ -1,77 +0,0 @@--- GenI surface realiser--- Copyright (C) 2005 Carlos Areces and Eric Kow------ This program is free software; you can redistribute it and/or--- modify it under the terms of the GNU General Public License--- as published by the Free Software Foundation; either version 2--- of the License, or (at your option) any later version.------ This program is distributed in the hope that it will be useful,--- but WITHOUT ANY WARRANTY; without even the implied warranty of--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the--- GNU General Public License for more details.------ You should have received a copy of the GNU General Public License--- along with this program; if not, write to the Free Software--- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.--{-# LANGUAGE ForeignFunctionInterface #-}---- | The SysGeni module mainly exists for running GenI as an application bundle--- under MacOS X. We mostly re-export stuff from System.Process, but if we--- are in a MacOS X application bundle, then we add @../Resources/bin@--- to the path for the miscellaneous resources that we ship with with GenI.-module NLP.GenI.SysGeni-where--import qualified System.Process as S--import Data.List (isSuffixOf)-import System.FilePath-import System.IO (Handle)-import System.Exit (ExitCode)--#ifdef __GLASGOW_HASKELL__-import Foreign-import Foreign.C-import Control.Monad-#include "ghcconfig.h"-#endif---- * Running a process--waitForProcess :: S.ProcessHandle -> IO ExitCode-waitForProcess = S.waitForProcess---- | One thing special we need to do for Macs is to detect if we're--- running from an application bundle. If we are, we assume that any--- processes we want to run are in @../Resources/bin@.-runInteractiveProcess :: String -> [String]- -> Maybe FilePath- -> Maybe [(String, String)]- -> IO (Handle, Handle, Handle, S.ProcessHandle)-runInteractiveProcess cmd args x y = do- dirname <- getProgDirName- -- detect if we're in an .app bundle, i.e. if - -- we are running from something.app/Contents/MacOS- let appBundle = ".app/Contents/MacOS/"- resBinCmd = "../Resources/bin" </> cmd- -- if we're in an .app bundle, we should prefix the- -- path with ../Resources/bin- let cmd2 = if appBundle `isSuffixOf` dirname - then resBinCmd else cmd- S.runInteractiveProcess cmd2 args x y ---- * Process helpers--foreign import ccall unsafe "getProgArgv"- getProgArgv :: Ptr CInt -> Ptr (Ptr CString) -> IO ()--getProgDirName :: IO String-getProgDirName = - alloca $ \ p_argc ->- alloca $ \ p_argv -> do- getProgArgv p_argc p_argv- argv <- peek p_argv- s <- peekElemOff argv 0 >>= peekCString- return $ takeDirectory s
+ src/NLP/GenI/Tag.hs view
@@ -0,0 +1,396 @@+-- GenI surface realiser+-- Copyright (C) 2005 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++-- | This module provides basic datatypes specific to Tree Adjoining Grammar+-- (TAG) elementary trees and some low-level operations.++{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}++module NLP.GenI.Tag (+ -- Main Datatypes+ Tags, TagElem(..), TagItem(..), TagSite(..),+ TagDerivation, DerivationStep(..), dsChild, dsParent, dsParentSite,+ ts_synIncomplete, ts_semIncomplete, ts_tbUnificationFailure,+ ts_rootFeatureMismatch,++ -- Functions from Tags+ addToTags, tagLeaves, getLexeme, toTagSite,++ -- Functions from TagElem+ setTidnums, plugTree, spliceTree,++ -- General functions+ mapBySem,+ collect, detectSites,+) where++import Control.Applicative ( (<$>), (<*>) )+import qualified Data.Map as Map+import Data.Maybe (fromMaybe, listToMaybe, mapMaybe, catMaybes)+import Data.Tree+import Data.Text ( Text )+import qualified Data.Text as T++import Control.DeepSeq+import Data.Generics (Data)+import Data.Typeable (Typeable)+import Data.FullList hiding ( (++) )+import Text.JSON++import NLP.GenI.FeatureStructure ( AvPair(..), Flist )+import NLP.GenI.General (listRepNode, groupByFM, preTerminals, geniBug)+import NLP.GenI.GeniShow+import NLP.GenI.GeniVal ( GeniVal(..), DescendGeniVal(..), Collectable(..), Idable(..),+ isConst,+ )+import NLP.GenI.Polarity.Types ( PolarityKey(..), SemPols )+import NLP.GenI.Pretty+import NLP.GenI.Semantics ( Sem, Literal(..), emptyLiteral )+import NLP.GenI.TreeSchema+ ( Ptype(..), GNode(..), GType(..), NodeName, lexemeAttributes )++-- ----------------------------------------------------------------------+-- Tags+-- ----------------------------------------------------------------------++-- | An anchored grammar.+-- The grammar associates a set of semantic predicates to a list of trees each.+type Tags = Map.Map String [TagElem] ++-- | 'addTags' @tags key elem@ adds @elem@ to the the list of elements associated+-- to the key+addToTags :: Tags -> String -> TagElem -> Tags+addToTags t k e = Map.insertWith (++) k [e] t++-- ----------------------------------------------------------------------+-- TagElem+-- ----------------------------------------------------------------------++data TagSite = TagSite+ { tsName :: Text+ , tsUp :: Flist GeniVal+ , tsDown :: Flist GeniVal+ , tsOrigin :: Text+ }+ deriving (Eq, Ord, Data, Typeable)++data TagElem = TE+ { idname :: Text+ , ttreename :: Text+ , tidnum :: Integer+ , ttype :: Ptype+ , ttree :: Tree (GNode GeniVal)+ , tsemantics :: Sem+ -- optimisation stuff+ -- (polarity key to charge interval)+ , tpolarities :: Map.Map PolarityKey (Int,Int)+ , tinterface :: Flist GeniVal -- for idxconstraints (pol)+ , ttrace :: [Text]+ , tsempols :: [SemPols] -- ^ can be empty+ }+ deriving (Eq, Data, Typeable)++-- | Given a tree(GNode) returns a list of substitution or adjunction+-- nodes, as well as remaining nodes with a null adjunction constraint.+detectSites :: Tree (GNode GeniVal) -> ([NodeName], [NodeName], [NodeName])+detectSites t =+ ( sites isSub -- for substitution+ , sites (not.gaconstr) -- for adjunction+ , sites constrButNotSub -- for neither+ )+ where+ ns = flatten t+ sites match = map gnname . filter match $ ns+ isSub n = gtype n == Subs+ constrButNotSub n = gaconstr n && (not $ isSub n)++toTagSite :: GNode GeniVal -> TagSite+toTagSite n = TagSite (gnname n) (gup n) (gdown n) (gorigin n)++type TagDerivation = [ DerivationStep ]++data DerivationStep = SubstitutionStep Text Text Text+ | AdjunctionStep Text Text Text+ | InitStep Text+ deriving (Show, Ord, Eq)++dsOp :: DerivationStep -> Char+dsOp (SubstitutionStep {}) = 's'+dsOp (AdjunctionStep {}) = 'a'+dsOp (InitStep {}) = 'i'++dsChild :: DerivationStep -> Text+dsChild (SubstitutionStep c _ _) = c+dsChild (AdjunctionStep c _ _ ) = c+dsChild (InitStep c) = c++dsParent :: DerivationStep -> Maybe Text+dsParent (SubstitutionStep _ p _) = Just p+dsParent (AdjunctionStep _ p _) = Just p+dsParent (InitStep _) = Nothing++dsParentSite :: DerivationStep -> Maybe Text+dsParentSite (SubstitutionStep _ _ s) = Just s+dsParentSite (AdjunctionStep _ _ s) = Just s+dsParentSite (InitStep _) = Nothing++instance JSON DerivationStep where+ readJSON j = do+ jo <- fromJSObject `fmap` readJSON j+ let field x = maybe (fail $ "Could not find: " ++ x) readJSON+ $ lookup x jo+ op <- field "op"+ child <- field "child"+ case op of+ "s" -> AdjunctionStep child <$> field "parent" <*> field "parent-node"+ "a" -> SubstitutionStep child <$> field "parent" <*> field "parent-node"+ "i" -> return (InitStep child)+ x -> fail $ "Don't know about derivation operation '" ++ x ++ "'"+ showJSON x =+ JSObject . toJSObject $ [ ("op", showJSON $ dsOp x)+ , ("child", showJSON $ dsChild x)+ ] ++ catMaybes+ [ (\v -> ("parent", showJSON v)) <$> dsParent x+ , (\v -> ("parent-node", showJSON v)) <$> dsParentSite x+ ]++instance Ord TagElem where+ compare t1 t2 = + case (ttype t1, ttype t2) of+ (Initial, Initial) -> compareId + (Initial, Auxiliar) -> LT+ (Auxiliar, Initial) -> GT+ (Auxiliar, Auxiliar) -> compareId + where compareId = compare (tidnum t1) (tidnum t2)++instance DescendGeniVal TagElem where+ descendGeniVal s te =+ te { tinterface = descendGeniVal s (tinterface te)+ , ttree = descendGeniVal s (ttree te)+ , tsemantics = descendGeniVal s (tsemantics te) }++instance DescendGeniVal TagSite where+ descendGeniVal s (TagSite n fu fd o) = TagSite n (descendGeniVal s fu) (descendGeniVal s fd) o++instance Collectable TagElem where+ collect t = (collect $ tinterface t) . (collect $ ttree t) + . (collect $ tsemantics t)++instance Idable TagElem where+ idOf = tidnum++-- Substitution and Adjunction++-- | Plug the first tree into the second tree at the specified node.+-- Anything below the second node is silently discarded.+-- We assume the trees are pluggable; it is treated as a bug if+-- they are not!+plugTree :: Tree NodeName+ -> NodeName+ -> Tree NodeName+ -> Tree NodeName+plugTree male n female =+ case listRepNode (const male) (nmatch n) [female] of+ ([r], True) -> r+ _ -> geniBug oops+ where+ oops = "plugTree: unexpected plug failure at node " ++ T.unpack n++-- | Given two trees 'auxt' and 't', splice the tree 'auxt' into+-- 't' via the TAG adjunction rule.+spliceTree :: NodeName -- ^ foot node of the aux tree+ -> Tree NodeName -- ^ aux tree+ -> NodeName -- ^ place to adjoin in target tree+ -> Tree NodeName -- ^ target tree+ -> Tree NodeName+spliceTree f auxT n top =+ plugTree middle n top + where+ bottom = fromMaybe (geniBug oops) (findSubTree n top)+ middle = plugTree bottom f auxT+ oops = unwords+ [ "NLP.GenI.Tag.spliceTree:"+ , "Unexpected adjunction failure."+ , "Could not find node " ++ T.unpack n ++ " of target tree."+ ]++nmatch :: NodeName -> Tree NodeName -> Bool+nmatch n (Node a _) = a == n++findSubTree :: NodeName -> Tree NodeName -> Maybe (Tree NodeName)+findSubTree n n2@(Node x ks)+ | x == n = Just n2+ | otherwise = case mapMaybe (findSubTree n) ks of+ [] -> Nothing+ (h:_) -> Just h++-- Unique ID++-- | Assigns a unique id to each element of this list, that is, an integer+-- between 1 and the size of the list.+setTidnums :: [TagElem] -> [TagElem]+setTidnums xs = zipWith (\c i -> setOrigin $ c {tidnum = i}) xs [1..]++setOrigin :: TagElem -> TagElem+setOrigin te =+ te { ttree = fmap setLabel . ttree $ te }+ where+ setLabel g = g { gorigin = nameNumber }+ nameNumber = idname te+ `T.append` ":"+ `T.append` (T.pack . show . tidnum) te++-- ----------------------------------------------------------------------+-- TAG Item+-- ----------------------------------------------------------------------++-- | 'TagItem' is a generalisation of 'TagElem'.+class TagItem t where + tgIdName :: t -> Text+ tgIdNum :: t -> Integer+ tgSemantics :: t -> Sem+ tgTree :: t -> Tree (GNode GeniVal)++instance TagItem TagElem where+ tgIdName = idname+ tgIdNum = tidnum+ tgSemantics = tsemantics+ tgTree = ttree++-- | Sorts trees into a Map.Map organised by the first literal of their+-- semantics. This is useful in at least three places: the polarity+-- optimisation, the gui display code, and code for measuring the efficiency+-- of GenI. Note: trees with a null semantics are filed under an empty+-- predicate, if any.+mapBySem :: (TagItem t) => [t] -> Map.Map (Literal GeniVal) [t]+mapBySem ts = + let gfn t = case tgSemantics t of+ [] -> emptyLiteral+ (x:_) -> x+ in groupByFM gfn ts++-- ----------------------------------------------------------------------+-- Extracting sentences+-- ----------------------------------------------------------------------++type UninflectedDisjunction = ([Text], Flist GeniVal)++-- | Normally, extracting the sentences from a TAG tree would just+-- consist of reading its leaves. But if you want the generator to+-- return inflected forms instead of just lemmas, you also need to+-- return the relevant features for each leaf. In TAG, or at least our+-- use of it, the features come from the *pre-terminal* nodes, that is,+-- not the leaves themselves but their parents. Another bit of+-- trickiness: because of atomic disjunction, leaves might have more+-- than one value, so we can't just return a String lemma but a list of+-- String, one for each possibility.+tagLeaves :: TagElem -> [ (NodeName, UninflectedDisjunction) ]+tagLeaves te = [ (gnname pt, (getLexeme t, gup pt)) | (pt,t) <- preTerminals . ttree $ te ]++-- | Try in order: lexeme, lexeme attributes, node name+getLexeme :: GNode GeniVal -> [Text]+getLexeme node =+ case glexeme node of+ [] -> fromMaybe [gnname node] $ firstMaybe grab lexemeAttributes+ lexs -> lexs+ where+ grab la = firstMaybe match guppy+ where+ match (AvPair a v) | isConst v && a == la =+ fromFL <$> gConstraints v+ match _ = Nothing+ guppy = gup node++firstMaybe :: (a -> Maybe b) -> [a] -> Maybe b+firstMaybe fn = listToMaybe . mapMaybe fn++-- ----------------------------------------------------------------------+-- Conversion to text+-- ----------------------------------------------------------------------++instance GeniShow TagElem where+ geniShowText te = T.concat+ [ "% ------------------------- ", idname te+ , "\n", ttreename te, ":" , idname te+ , " " , (geniShowText $ tinterface te)+ , " " , (geniShowText $ ttype te)+ , "\n", (geniShowText $ ttree te)+ , "\n", geniKeyword "semantics" (geniShowText $ tsemantics te)+ ]++instance GeniShow [TagElem] where+ geniShowText = T.intercalate "\n\n" . map geniShowText++-- Useful for debugging adjunction and substitution nodes+instance Pretty [TagSite] where+ pretty =+ T.intercalate "\n " . map fn+ where+ fn (TagSite n t b o) = T.intercalate "/"+ [ n, pretty t, pretty b, o ]++-- ----------------------------------------------------------------------+-- Diagnostic messages+--+-- Diagnostic messages let us know why a TAG tree is not returned as a result.+-- Whenever GenI decides to discard a tree, it sets the tdiagnostic field of +-- the TagElem so that the person using a debugger can find out what went wrong.+-- ----------------------------------------------------------------------++ts_synIncomplete, ts_tbUnificationFailure :: String+ts_synIncomplete = "syntactically incomplete"+ts_tbUnificationFailure = "top/bot unification failure"++ts_rootFeatureMismatch :: Flist GeniVal -> String+ts_rootFeatureMismatch good = "root feature does not unify with " ++ prettyStr good++ts_semIncomplete :: [Literal GeniVal] -> String+ts_semIncomplete sem = "semantically incomplete - missing: " ++ prettyStr sem++-- ----------------------------------------------------------------------+-- Performance+-- ----------------------------------------------------------------------++{-!+deriving instance NFData TagElem+deriving instance NFData DerivationStep+!-}++-- GENERATED START++ +instance NFData TagElem where+ rnf (TE x1 x2 x3 x4 x5 x6 x7 x8 x9 x10)+ = rnf x1 `seq`+ rnf x2 `seq`+ rnf x3 `seq`+ rnf x4 `seq`+ rnf x5 `seq`+ rnf x6 `seq`+ rnf x7 `seq` rnf x8 `seq` rnf x9 `seq` rnf x10 `seq` ()++ +instance NFData DerivationStep where+ rnf (SubstitutionStep x1 x2 x3)+ = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` ()+ rnf (AdjunctionStep x1 x2 x3)+ = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` ()+ rnf (InitStep x1) = rnf x1 `seq` ()+-- GENERATED STOP
− src/NLP/GenI/Tags.lhs
@@ -1,380 +0,0 @@-% GenI surface realiser-% Copyright (C) 2005 Carlos Areces and Eric Kow-%-% This program is free software; you can redistribute it and/or-% modify it under the terms of the GNU General Public License-% as published by the Free Software Foundation; either version 2-% of the License, or (at your option) any later version.-%-% This program is distributed in the hope that it will be useful,-% but WITHOUT ANY WARRANTY; without even the implied warranty of-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-% GNU General Public License for more details.-%-% You should have received a copy of the GNU General Public License-% along with this program; if not, write to the Free Software-% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.--\chapter{Tags}-\label{cha:Tags}--This module provides basic datatypes specific to Tree Adjoining Grammar-(TAG) and some low-level operations. Note that we don't handle-substitution and adjunction here; see sections \ref{sec:substitution}-and \ref{sec:adjunction} instead.--\begin{code}-{-# LANGUAGE TemplateHaskell #-}--module NLP.GenI.Tags(- -- Main Datatypes- Tags, TagElem(..), TagItem(..), TagSite(..),- TagDerivation, DerivationStep(..), emptyTE,- ts_synIncomplete, ts_semIncomplete, ts_tbUnificationFailure,- ts_rootFeatureMismatch,-- -- Functions from Tags- addToTags, tagLeaves,-- -- Functions from TagElem- setTidnums, -- -- General functions- mapBySem, subsumedBy, showTagSites,- collect, detectSites-) where-\end{code}--\ignore{-\begin{code}-import Control.Applicative ( (<$>), (<*>) )-import qualified Data.Map as Map-import Data.Maybe (fromMaybe, listToMaybe, mapMaybe)-import Data.List (intersperse)-import Data.Tree--import Data.Generics (Data)-import Data.Generics.PlateDirect-import Data.Typeable (Typeable)-import Text.JSON--import NLP.GenI.Btypes (Ptype(Initial, Auxiliar), SemPols,- GeniVal(GConst), AvPair(..),- GNode(gup, glexeme, gnname, gaconstr, gdown, gtype, gorigin),- GType(Subs), Flist,- DescendGeniVal(..),- Collectable(..), Idable(..),- Sem, Pred, emptyPred, - emptyGNode,- showFlist, showPairs, showSem, lexemeAttributes,- )-import NLP.GenI.General (groupByFM, preTerminals)-import NLP.GenI.PolarityTypes (PolarityKey(..))-\end{code}-}--% -----------------------------------------------------------------------\section{Tags}-% ------------------------------------------------------------------------\begin{code}--- | An anchored grammar.--- The grammar associates a set of semantic predicates to a list of trees each.-type Tags = Map.Map String [TagElem] ---- | 'addTags' @tags key elem@ adds @elem@ to the the list of elements associated--- to the key-addToTags :: Tags -> String -> TagElem -> Tags-addToTags t k e = Map.insertWith (++) k [e] t-\end{code}--% -----------------------------------------------------------------------\section{TagElem}-% ------------------------------------------------------------------------Final types used for the combined macros + lexicon. We assume that-a two trees are the same iff they have the same tidnum. To make this-work, we assign each tree with a unique id during the process of-combining macros with lexicon (see section \ref{sec:combine_macros}).--\begin{code}-data TagSite = TagSite { tsName :: String- , tsUp :: Flist- , tsDown :: Flist- , tsOrigin :: String- }- deriving (Show, Eq, Ord, Data, Typeable)--instance Biplate TagSite GeniVal where- biplate (TagSite x1 zu zd x2) = plate TagSite |- x1 ||+ zu ||+ zd |- x2--instance Biplate (Maybe TagSite) GeniVal where- biplate (Just x1) = plate Just |+ x1- biplate Nothing = plate Nothing--data TagElem = TE {- idname :: String,- ttreename :: String,- tidnum :: Integer,- ttype :: Ptype,- ttree :: Tree GNode,- tsemantics :: Sem,- -- optimisation stuff- -- (polarity key to charge interval)- tpolarities :: Map.Map PolarityKey (Int,Int),- tinterface :: Flist, -- for idxconstraints (pol)- ttrace :: [String],- tsempols :: [SemPols]- }- deriving (Show, Eq, Data, Typeable)--instance Biplate TagElem GeniVal where- biplate (TE x1 x2 x3 x4 zt zsem x5 zint x6 x7) =- plate TE |- x1 |- x2 |- x3 |- x4- |+ zt- ||+ zsem |- x5- ||+ zint |- x6 |- x7-\end{code}--A TAG derivation history consists of a list of 3-tuples representing the-operation (s for substitution, a for adjunction), the name of the child tree,-the name of the parent tree and the node affected.--\begin{code}-type TagDerivation = [ DerivationStep ]--data DerivationStep = DerivationStep- { dsOp :: Char- , dsChild :: String- , dsParent :: String- , dsParentSite :: String- } deriving (Show, Ord, Eq)--instance JSON DerivationStep where- readJSON j =- do jo <- fromJSObject `fmap` readJSON j- let field x = maybe (fail $ "Could not find: " ++ x) readJSON- $ lookup x jo- DerivationStep <$> field "op"- <*> field "child"- <*> field "parent"- <*> field "parent-node"- showJSON x =- JSObject . toJSObject $ [ ("op", showJSON $ dsOp x)- , ("child", showJSON $ dsChild x)- , ("parent", showJSON $ dsParent x)- , ("parent-node", showJSON $ dsParentSite x)- ]-\end{code}--\begin{code}-instance Ord TagElem where- compare t1 t2 = - case (ttype t1, ttype t2) of- (Initial, Initial) -> compareId - (Initial, Auxiliar) -> LT- (Auxiliar, Initial) -> GT- (Auxiliar, Auxiliar) -> compareId - _ -> error "TagElem compare not exhaustively defined"- where compareId = compare (tidnum t1) (tidnum t2)--instance DescendGeniVal TagElem where- descendGeniVal s te =- te { tinterface = descendGeniVal s (tinterface te)- , ttree = descendGeniVal s (ttree te)- , tsemantics = descendGeniVal s (tsemantics te) }--instance DescendGeniVal TagSite where- descendGeniVal s (TagSite n fu fd o) = TagSite n (descendGeniVal s fu) (descendGeniVal s fd) o--instance Collectable TagElem where- collect t = (collect $ tinterface t) . (collect $ ttree t) - . (collect $ tsemantics t)--instance Idable TagElem where- idOf = tidnum-\end{code}--\begin{code}-emptyTE :: TagElem-emptyTE = TE { idname = "",- ttreename = "",- tidnum = -1,- ttype = Initial,- ttree = Node emptyGNode [],- tsemantics = [], - tpolarities = Map.empty,- tsempols = [],- tinterface = [],- ttrace = []- }---- | Given a tree(GNode) returns a list of substitution or adjunction--- nodes, as well as remaining nodes with a null adjunction constraint.-detectSites :: Tree GNode -> ([TagSite], [TagSite], [TagSite])-detectSites t =- ( sites isSub -- for substitution- , sites (not.gaconstr) -- for adjunction- , sites constrButNotSub -- for neither- )- where- ns = flatten t- sites match = [ TagSite (gnname n) (gup n) (gdown n) (gorigin n) | n <- ns, match n ]- isSub n = gtype n == Subs- constrButNotSub n = gaconstr n && (not $ isSub n)-\end{code}--\subsection{Unique ID}--TagElem comparison relies exclusively on \fnparam{tidnum}, so you must-ensure that every TagElem you use has a unique ID. We provide two-helpful functions for this. These are most likely useful \emph{between}-lexical selection and generation proper, because during generation-proper, you can simply keep a counter within a State monad to assign-unique IDs to new TagElems.--Note that we also label each node of the tree with its elementary tree-name and with the unique ID. This helps us to build derivation trees-correctly--\begin{code}--- | Assigns a unique id to each element of this list, that is, an integer--- between 1 and the size of the list.-setTidnums :: [TagElem] -> [TagElem]-setTidnums xs = zipWith (\c i -> setOrigin $ c {tidnum = i}) xs [1..]--setOrigin :: TagElem -> TagElem-setOrigin te = te { ttree = fmap setLabel . ttree $ te }- where setLabel g = g { gorigin = idname te ++ ":" ++ (show.tidnum) te }-\end{code}--% -----------------------------------------------------------------------\section{TAG Item}-% ------------------------------------------------------------------------\begin{code}--- | 'TagItem' is a generalisation of 'TagElem'.-class TagItem t where - tgIdName :: t -> String- tgIdNum :: t -> Integer- tgSemantics :: t -> Sem--instance TagItem TagElem where- tgIdName = idname- tgIdNum = tidnum- tgSemantics = tsemantics-\end{code}--% -----------------------------------------------------------------------\section{Map by sem}-% ------------------------------------------------------------------------\begin{code}--- | Sorts trees into a Map.Map organised by the first literal of their--- semantics. This is useful in at least three places: the polarity--- optimisation, the gui display code, and code for measuring the efficiency--- of GenI. Note: trees with a null semantics are filed under an empty--- predicate, if any.-mapBySem :: (TagItem t) => [t] -> Map.Map Pred [t]-mapBySem ts = - let gfn t = case tgSemantics t of- [] -> emptyPred- (x:_) -> x- in groupByFM gfn ts---- | 'subsumedBy' @cs ts@ determines if the candidate semantics @cs@ is--- subsumed by the proposition semantics @ts@. Notice how the proposition--- semantics is only a single item where as the candidate semantics is a--- list.------ We assume------ * most importantly that @cs@ has already its semantics instatiated--- (all variables assigned)------ * @cs@ and @ts@ are sorted------ * the list in each element of cs and ts is itself sorted -subsumedBy :: Sem -> Pred -> Bool -subsumedBy [] _ = False -subsumedBy ((ch, cp, cla):cl) (th, tp,tla)- | (ch == th) && (cp == tp) && (cla == tla) = True - -- if we haven't yet overshot, try for the next one- | cp < tp = subsumedBy cl (th, tp, tla)- | otherwise = False-\end{code}--% -----------------------------------------------------------------------\section{Extracting sentences}-% ------------------------------------------------------------------------Normally, extracting the sentences from a TAG tree would just consist of-reading its leaves. But if you want the generator to return inflected-forms instead of just lemmas, you also need to return the relevant-features for each leaf. In TAG, or at least our use of it, the features-come from the \emph{pre-terminal} nodes, that is, not the leaves-themselves but their parents. Another bit of trickiness: because of-atomic disjunction, leaves might have more than one value, so we can't-just return a String lemma but a list of String, one for each-possibility.--\begin{code}-type UninflectedDisjunction = ([String], Flist)--tagLeaves :: TagElem -> [ (String, UninflectedDisjunction) ]-tagLeaves te = [ (gnname pt, (getLexeme t, gup pt)) | (pt,t) <- preTerminals . ttree $ te ]---- | Try in order: lexeme, lexeme attributes, node name-getLexeme :: GNode -> [String]-getLexeme node =- case glexeme node of- [] -> fromMaybe [gnname node] $ firstMaybe grab lexemeAttributes- lexs -> lexs- where- grab la =- let match (AvPair a (GConst v)) | a == la = Just v- match _ = Nothing- in firstMaybe match guppy- guppy = gup node--firstMaybe :: (a -> Maybe b) -> [a] -> Maybe b-firstMaybe fn = listToMaybe . mapMaybe fn--\end{code}--% -----------------------------------------------------------------------\section{Debugging}-% ------------------------------------------------------------------------\begin{code}--- Useful for debugging adjunction and substitution nodes-showTagSites :: [TagSite] -> String-showTagSites sites = concat $ intersperse "\n " $ map fn sites- where- fn (TagSite n t b o) =- concat . intersperse "/" $ [ n, showPairs t, showPairs b, o ]-\end{code}--% -----------------------------------------------------------------------\section{Diagnostic messages}-% ------------------------------------------------------------------------Diagnostic messages let us know why a TAG tree is not returned as a result.-Whenever GenI decides to discard a tree, it sets the tdiagnostic field of -the TagElem so that the person using a debugger can find out what went wrong.--\begin{code}-ts_synIncomplete, ts_tbUnificationFailure :: String-ts_synIncomplete = "syntactically incomplete"-ts_tbUnificationFailure = "top/bot unification failure"--ts_rootFeatureMismatch :: Flist -> String-ts_rootFeatureMismatch good = "root feature does not unify with " ++ showFlist good--ts_semIncomplete :: [Pred] -> String-ts_semIncomplete sem = "semantically incomplete - missing: " ++ showSem sem-\end{code}--% -----------------------------------------------------------------------% Performance-% ----------------------------------------------------------------------
− src/NLP/GenI/Test.hs
@@ -1,31 +0,0 @@--- ------------------------------------------------------------------------- GenI surface realiser--- Copyright (C) 2009 Eric Kow------ This program is free software; you can redistribute it and/or--- modify it under the terms of the GNU General Public License--- as published by the Free Software Foundation; either version 2--- of the License, or (at your option) any later version.------ This program is distributed in the hope that it will be useful,--- but WITHOUT ANY WARRANTY; without even the implied warranty of--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the--- GNU General Public License for more details.------ You should have received a copy of the GNU General Public License--- along with this program; if not, write to the Free Software--- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.--- ------------------------------------------------------------------------module NLP.GenI.Test where--import System.Environment ( getArgs )-import Test.Framework-import NLP.GenI.GeniVal ( testSuite )--runTests :: IO ()-runTests =- do args <- filter (/= "--unit-tests") `fmap` getArgs- flip defaultMainWithArgs args- [ NLP.GenI.GeniVal.testSuite- ]
+ src/NLP/GenI/TestSuite.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE OverloadedStrings #-}+-- GenI surface realiser+-- Copyright (C) 2005-2009 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++module NLP.GenI.TestSuite+where++import Data.Text ( Text)+import qualified Data.Text as T++import NLP.GenI.GeniShow+import NLP.GenI.Pretty+import NLP.GenI.Semantics++data TestCase = TestCase+ { tcName :: Text+ , tcSemString :: Text -- ^ for gui+ , tcSem :: SemInput+ , tcExpected :: [Text] -- ^ expected results (for testing)+ }++instance GeniShow TestCase where+ geniShowText (TestCase { tcName = name+ , tcExpected = sentences+ , tcSemString = semStr+ , tcSem = sem+ }) =+ T.unlines $ [ name, geniShowText sem ]+ ++ map (geniKeyword "sentence" . squares) sentences++instance Pretty TestCase where+ pretty = geniShowText
+ src/NLP/GenI/TreeSchema.hs view
@@ -0,0 +1,351 @@+-- GenI surface realiser+-- Copyright (C) 2005-2009 Carlos Areces and Eric Kow+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE OverlappingInstances, FlexibleInstances #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}++-- | This module provides basic datatypes specific to Tree Adjoining Grammar+-- tree schemata.+module NLP.GenI.TreeSchema (+ Macros,+ SchemaTree, SchemaNode, Ttree(..), Ptype(..),++ -- Functions from Tree GNode+ root, rootUpd, foot, setLexeme, setAnchor, lexemeAttributes,+ crushTreeGNode,++ -- GNode+ GNode(..), gnnameIs, NodeName,+ GType(..), gCategory, showLexeme,+ crushGNode,+ ) where++import qualified Data.Map as Map+import Data.Binary+import Data.Tree+import Data.Text ( Text )+import qualified Data.Text as T++import Control.DeepSeq+import Data.FullList hiding (head, tail, (++))+import Data.Generics (Data)+import Data.Typeable (Typeable)++import NLP.GenI.General (filterTree, listRepNode, geniBug, quoteText)+import NLP.GenI.GeniShow+import NLP.GenI.GeniVal ( GeniVal(..), DescendGeniVal(..), Collectable(..),+ )+import NLP.GenI.FeatureStructure ( AvPair(..), Flist, crushFlist )+import NLP.GenI.Pretty+import NLP.GenI.Semantics ( Sem )++-- ----------------------------------------------------------------------+-- Tree schemata++-- In GenI, the tree schemata are called `macros' for historical reasons.+-- We are working to phase out this name in favour of the more standard+-- `tree schema(ta)'.+-- ----------------------------------------------------------------------++type SchemaTree = Ttree SchemaNode+type SchemaNode = GNode [GeniVal]+type Macros = [SchemaTree]++data Ttree a = TT+ { params :: [GeniVal]+ , pfamily :: Text+ , pidname :: Text+ , pinterface :: Flist GeniVal+ , ptype :: Ptype+ , psemantics :: Maybe Sem+ , ptrace :: [Text]+ , tree :: Tree a+ }+ deriving (Data, Typeable, Eq)++data Ptype = Initial | Auxiliar+ deriving (Show, Eq, Data, Typeable)++instance DescendGeniVal v => DescendGeniVal (Ttree v) where+ descendGeniVal s mt =+ mt { params = descendGeniVal s (params mt)+ , tree = descendGeniVal s (tree mt)+ , pinterface = descendGeniVal s (pinterface mt)+ , psemantics = descendGeniVal s (psemantics mt) }++instance (Collectable a) => Collectable (Ttree a) where+ collect mt = (collect $ params mt) . (collect $ tree mt) .+ (collect $ psemantics mt) . (collect $ pinterface mt)++-- ----------------------------------------------------------------------+-- Tree manipulation+-- ----------------------------------------------------------------------++-- Traversal++instance DescendGeniVal a => DescendGeniVal (Map.Map k a) where+ descendGeniVal s = {-# SCC "descendGeniVal" #-} Map.map (descendGeniVal s)++instance (Collectable a => Collectable (Tree a)) where+ collect = collect.flatten++-- Utility functions++root :: Tree a -> a+root (Node a _) = a++rootUpd :: Tree a -> a -> Tree a+rootUpd (Node _ l) b = (Node b l)++foot :: Tree (GNode a) -> GNode a+foot t = case filterTree (\n -> gtype n == Foot) t of+ [x] -> x+ _ -> geniBug $ "foot returned weird result"++-- | Given a lexical item @s@ and a Tree GNode t, returns the tree t'+-- where l has been assigned to the anchor node in t'+setAnchor :: FullList Text -> Tree (GNode a) -> Tree (GNode a)+setAnchor s t =+ let filt (Node a []) = (gtype a == Lex && ganchor a)+ filt _ = False+ in case listRepNode (setLexeme (fromFL s)) filt [t] of+ ([r],True) -> r+ _ -> geniBug $ "setLexeme " ++ show s ++ " returned weird result"++-- | Given a lexical item @l@ and a tree node @n@ (actually a subtree+-- with no children), return the same node with the lexical item as+-- its unique child. The idea is that it converts terminal lexeme nodes+-- into preterminal nodes where the actual terminal is the given lexical+-- item+setLexeme :: [Text] -> Tree (GNode a) -> Tree (GNode a)+setLexeme l (Node a []) = Node a [ Node subanc [] ]+ where+ subanc = GN+ { gnname = T.concat $ "_" : gnname a : "." : l+ , gup = []+ , gdown = []+ , gaconstr = True+ , ganchor = False+ , glexeme = l+ , gtype = Other+ , gorigin = ""+ }+setLexeme _ _ = geniBug "impossible case in setLexeme - subtree with kids"++-- ----------------------------------------------------------------------+-- TAG nodes (GNode)+-- ----------------------------------------------------------------------++-- | A single node of a TAG tree.+data GNode gv = GN+ { gnname :: NodeName+ , gup :: Flist gv -- ^ top feature structure+ , gdown :: Flist gv -- ^ bottom feature structure+ , ganchor :: Bool -- ^ @False@ for na nodes+ , glexeme :: [Text] -- ^ @[]@ for na nodes+ , gtype :: GType+ , gaconstr :: Bool+ , gorigin :: Text -- ^ for TAG, this would be the elementary tree+ -- that this node originally came from+ }+ deriving (Eq, Data, Typeable)++-- Node type used during parsing of the grammar+data GType = Subs | Foot | Lex | Other+ deriving (Show, Eq, Data, Typeable)++type NodeName = Text++-- Traversal++instance Collectable gv => Collectable (GNode gv) where+ collect n = (collect $ gdown n) . (collect $ gup n)++instance DescendGeniVal v => DescendGeniVal (GNode v) where+ descendGeniVal s gn =+ gn { gup = descendGeniVal s (gup gn)+ , gdown = descendGeniVal s (gdown gn) }++-- Utilities++gnnameIs :: NodeName -> GNode gv -> Bool+gnnameIs n = (== n) . gnname++-- | Return the value of the "cat" attribute, if available+gCategory :: Flist GeniVal -> Maybe GeniVal+gCategory top =+ case [ v | AvPair "cat" v <- top ] of+ [] -> Nothing+ [c] -> Just c+ _ -> geniBug $ "Impossible case: node with more than one category"++-- | Attributes recognised as lexemes, in order of preference+lexemeAttributes :: [Text]+lexemeAttributes = [ "lex", "phon", "cat" ]++-- ----------------------------------------------------------------------+-- Pretty printing and other text conversions+-- ----------------------------------------------------------------------++instance GeniShow Ptype where+ geniShow Initial = "initial"+ geniShow Auxiliar = "auxiliary"++instance (GeniShow a) => GeniShow (Ttree a) where+ geniShowText tt = T.intercalate "\n" . filter (not . T.null) $+ [ "% ------------------------- ", pidname tt+ , T.unwords [ pfamily tt <> ":" <> pidname tt+ , plist+ , geniShowText (ptype tt)+ ]+ , geniShowText (tree tt)+ , maybe "" showSem (psemantics tt)+ , showTr (ptrace tt)+ ]+ where+ plist = parens . T.unwords . concat $+ [ map geniShowText (params tt)+ , ["!"]+ , map geniShowText (pinterface tt)+ ]+ showSem = geniKeyword "semantics" . geniShowText+ showTr = geniKeyword "trace" . squares . T.unwords++-- | The default show for GNode tries to be very compact; it only shows the value+-- for cat attribute and any flags which are marked on that node.+--+-- This is one the places where the pretty representation of a GenI object is+-- different from its GenI-format one+instance Pretty (GNode GeniVal) where+ pretty gn =+ stub `T.append` extra+ where+ cat_ = maybe "" pretty . gCategory $ gup gn+ lex_ = showLexeme (glexeme gn)+ --+ stub = T.intercalate ":" $ filter (not . T.null) [ cat_, lex_ ]+ extra = case gtype gn of+ Subs -> " !"+ Foot -> " *"+ _ -> if gaconstr gn then " #" else ""++instance GeniShow (GNode GeniVal) where+ geniShowText x =+ T.unwords . filter (not . T.null) $+ [ gnname x, gaconstrstr, gtypestr x, glexstr x, tbFeats x ]+ where+ gaconstrstr = case (gaconstr x, gtype x) of+ (True, Other) -> "aconstr:noadj"+ _ -> ""+ gtypestr n = case gtype n of+ Subs -> "type:subst"+ Foot -> "type:foot"+ Lex -> if ganchor n && (null.glexeme) n+ then "type:anchor" else "type:lex"+ _ -> ""+ glexstr n =+ if null ls+ then ""+ else T.intercalate "|" (map quoteText ls)+ where+ ls = glexeme n+ tbFeats n =+ geniShowText (gup n)+ `T.append` "!"+ `T.append` geniShowText (gdown n)+++-- FIXME: will have to think of nicer way - one which involves+-- unpacking the trees :-(+showLexeme :: [Text] -> Text+showLexeme [] = ""+showLexeme [l] = l+showLexeme xs = T.intercalate "|" xs++-- Fancy disjunction++crushTreeGNode :: Tree (GNode [GeniVal]) -> Maybe (Tree (GNode GeniVal))+crushTreeGNode (Node x xs) =+ do x2 <- crushGNode x+ xs2 <- mapM crushTreeGNode xs+ return $ Node x2 xs2++crushGNode :: GNode [GeniVal] -> Maybe (GNode GeniVal)+crushGNode gn =+ do gup2 <- crushFlist (gup gn)+ gdown2 <- crushFlist (gdown gn)+ return $ GN { gnname = gnname gn+ , gup = gup2+ , gdown = gdown2+ , ganchor = ganchor gn+ , glexeme = glexeme gn+ , gtype = gtype gn+ , gaconstr = gaconstr gn+ , gorigin = gorigin gn}+++instance Binary Ptype where+ put Initial = putWord8 0+ put Auxiliar = putWord8 1+ get = do+ tag_ <- getWord8+ case tag_ of+ 0 -> return Initial+ 1 -> return Auxiliar+ _ -> fail "no parse"++instance Binary gv => Binary (GNode gv) where+ put (GN a b c d e f g h) = put a >> put b >> put c >> put d >> put e >> put f >> put g >> put h+ get = get >>= \a -> get >>= \b -> get >>= \c -> get >>= \d -> get >>= \e -> get >>= \f -> get >>= \g -> get >>= \h -> return (GN a b c d e f g h)++instance Binary GType where+ put Subs = putWord8 0+ put Foot = putWord8 1+ put Lex = putWord8 2+ put Other = putWord8 3+ get = do+ tag_ <- getWord8+ case tag_ of+ 0 -> return Subs+ 1 -> return Foot+ 2 -> return Lex+ 3 -> return Other+ _ -> fail "no parse"++instance (Binary a) => Binary (Ttree a) where+ put (TT a b c d e f g h) = put a >> put b >> put c >> put d >> put e >> put f >> put g >> put h+ get = get >>= \a -> get >>= \b -> get >>= \c -> get >>= \d -> get >>= \e -> get >>= \f -> get >>= \g -> get >>= \h -> return (TT a b c d e f g h)++-- Node type used during parsing of the grammar+instance NFData GType where+ rnf x = x `seq` ()++instance NFData Ptype where+ rnf x = x `seq` ()++-- | A single node of a TAG tree.+instance NFData gv => NFData (GNode gv) where+ rnf (GN x1 x2 x3 x4 x5 x6 x7 x8)+ = rnf x1 `seq`+ rnf x2 `seq`+ rnf x3 `seq`+ rnf x4 `seq`+ rnf x5 `seq`+ rnf x6 `seq`+ rnf x7 `seq` rnf x8 `seq` ()
+ src/NLP/GenI/Warning.hs view
@@ -0,0 +1,32 @@+-- GenI surface realiser+-- Copyright (C) 2012 Eric Kow (Computational Linguistics Ltd)+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++-- | Typed warnings as an easier alternative to strings.+--+-- This makes it easier to recognise repeated warnings and print them+-- out in a reasonable way+module NLP.GenI.Warning+ ( -- * Collection of warnings+ GeniWarnings, fromGeniWarnings, mkGeniWarnings+ , sortWarnings+ -- * Individual warnings+ , GeniWarning(..), LexWarning(..)+ , showGeniWarning+ )+ where++import NLP.GenI.Warning.Internal
+ src/NLP/GenI/Warning/Internal.hs view
@@ -0,0 +1,146 @@+-- GenI surface realiser+-- Copyright (C) 2011 Eric Kow (on behalf of SRI)+--+-- This program is free software; you can redistribute it and/or+-- modify it under the terms of the GNU General Public License+-- as published by the Free Software Foundation; either version 2+-- of the License, or (at your option) any later version.+--+-- This program is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+-- GNU General Public License for more details.+--+-- You should have received a copy of the GNU General Public License+-- along with this program; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++{-# LANGUAGE OverloadedStrings #-}+module NLP.GenI.Warning.Internal where++import Data.FullList ( FullList, fromFL )+import Data.List+import Data.Monoid ( Monoid, mconcat, mappend, mempty )+import Data.Text ( Text )+import qualified Data.Map as Map+import qualified Data.Text as T++import Data.Poset++import NLP.GenI.General ( histogram )+import NLP.GenI.GeniVal ( GeniVal )+import NLP.GenI.LexicalSelection.Types ( LexCombineError, showLexCombineError )+import NLP.GenI.Lexicon ( LexEntry(..) )+import NLP.GenI.Pretty+import NLP.GenI.Semantics ( Literal )+import NLP.GenI.TreeSchema ( showLexeme )++-- | This exists because we want the 'Monoid' instance, providing a +-- GenI-specific notion of appending which merges instances of the+-- same error+newtype GeniWarnings = GeniWarnings { fromGeniWarnings :: [GeniWarning] }++mkGeniWarnings :: [GeniWarning] -> GeniWarnings+mkGeniWarnings = mconcat . map (\x -> GeniWarnings [x])++instance Monoid GeniWarnings where+ mempty = GeniWarnings []+ mappend (GeniWarnings g1) (GeniWarnings g2) = GeniWarnings (foldr appendWarning g2 g1)++data GeniWarning = -- | A warning that should be repeated for each lexical entry affected+ LexWarning [LexEntry] LexWarning+ -- | A single custom warning+ | CustomLexWarning Text+ -- | Literals which did not receive any lexical selection+ | NoLexSelection [Literal GeniVal]+ -- | Warnings from the morphological realiser+ | MorphWarning [Text]+ deriving (Eq)+++data LexWarning = LexCombineAllSchemataFailed+ | LexCombineOneSchemaFailed LexCombineError+ | MissingCoanchors Text Int+ deriving (Eq)++-- | Sort, treating non-comporable items as equal+posort :: Poset a => [a] -> [a]+posort = sortBy (flip fromPosetCmp)+ where+ fromPosetCmp x1 x2 = case posetCmp x1 x2 of+ Comp o -> o+ NComp -> EQ++instance Poset GeniWarning where+ -- 1. LexWarning+ leq (LexWarning _ w1) (LexWarning _ w2) = leq w1 w2+ leq (LexWarning _ _) _ = True+ -- 2. CustomLexWarning+ leq (CustomLexWarning _) (LexWarning _ _) = False+ leq (CustomLexWarning w1) (CustomLexWarning w2) = leq w1 w2+ leq (CustomLexWarning _) _ = True+ -- 3. NoLexSelection+ leq (NoLexSelection _) (LexWarning _ _) = False+ leq (NoLexSelection _) (CustomLexWarning _) = False+ leq (NoLexSelection _) (NoLexSelection _) = True+ leq (NoLexSelection _) _ = True+ -- 4. MorphWarning+ leq (MorphWarning _) (LexWarning _ _) = False+ leq (MorphWarning _) (CustomLexWarning _) = False+ leq (MorphWarning _) (NoLexSelection _) = False+ leq (MorphWarning w1) (MorphWarning w2) = leq w1 w2++instance Poset LexWarning where+ -- 1. LexCombineOneSchemaFailed+ leq (LexCombineOneSchemaFailed l1) (LexCombineOneSchemaFailed l2) = leq l1 l2+ leq (LexCombineOneSchemaFailed _) _ = True+ -- 2. LexCombineAllSchemataFailed+ leq LexCombineAllSchemataFailed (LexCombineOneSchemaFailed _) = False+ leq LexCombineAllSchemataFailed _ = True+ -- 3. MissingCoanchors+ leq (MissingCoanchors _ n1) (MissingCoanchors _ n2) = leq n1 n2+ leq (MissingCoanchors _ _) (LexCombineOneSchemaFailed _) = False+ leq (MissingCoanchors _ _) LexCombineAllSchemataFailed = False++sortWarnings :: GeniWarnings -> GeniWarnings+sortWarnings (GeniWarnings ws) = GeniWarnings (posort ws)++appendWarning :: GeniWarning -> [GeniWarning] -> [GeniWarning]+appendWarning w0 [] = [w0]+appendWarning w0 (w:ws) = case mergeWarning w0 w of+ Just w1 -> w1 : ws+ Nothing -> w : appendWarning w0 ws++mergeWarning :: GeniWarning -> GeniWarning -> Maybe GeniWarning+mergeWarning (LexWarning ls1 w1) (LexWarning ls2 w2) | w1 == w2 = Just (LexWarning (ls1 ++ ls2) w1)+mergeWarning _ _ = Nothing++-- | A warning may be displayed over several lines+showGeniWarning :: GeniWarning -> [Text]+showGeniWarning (NoLexSelection ps) =+ [ "No lexical entries for literals:" <+> T.unwords (map pretty ps) ]+showGeniWarning (CustomLexWarning w) = [w]+showGeniWarning (LexWarning ls wa) = do -- list monad+ wf <- Map.toList (toWfCount ls)+ return (msg <> ":" <+> prettyCount showWithFam "lemmas" wf <> suffix)+ where+ (msg, suffix) = showLexWarning wa+ showLexWarning LexCombineAllSchemataFailed =+ ("Lexically selected but anchoring failed for *all* instances of", "")+ showLexWarning (LexCombineOneSchemaFailed lc) =+ showLexCombineError lc+ showLexWarning (MissingCoanchors co n) =+ (T.unwords [ "Expected co-anchor", co+ , "is missing from", T.pack (show n), "schemata"+ ]+ , "")+ showWithFam (w, f) = showLexeme (fromFL w) <+> parens f+showGeniWarning (MorphWarning ws) = map ("Morph:" <+>) ws++-- word and all families associated with that word+type WordFamilyCount = Map.Map (FullList Text, Text) Int++toWfCount :: [LexEntry] -> WordFamilyCount+toWfCount = histogram . map toWf+ where+ toWf i = (iword i, ifamname i)