summaryrefslogtreecommitdiff
path: root/src/GF/Parsing/MCFG/Active.hs
blob: dd8516379d9b76ddd077c6a8f2895f2d14c554e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186

module GF.NewParsing.MCFG.Active (parse) where

import GF.NewParsing.GeneralChart
import GF.Formalism.GCFG
import GF.Formalism.MCFG
import GF.Formalism.Utilities
import GF.NewParsing.MCFG.Range
import GF.NewParsing.MCFG.PInfo
import GF.System.Tracing
import Monad (guard)

----------------------------------------------------------------------
-- * parsing

parse :: (Ord n, Ord c, Ord l, Ord t) => String -> MCFParser c n l t
parse strategy mcfg starts toks
    = [ Abs (cat, found) (zip rhs rrecs) fun |
	Final (Abs cat rhs fun) found rrecs <- chartLookup chart Fin ]
    where chart = process strategy mcfg starts toks

process :: (Ord n, Ord c, Ord l, Ord t) => 
	   String -> MCFGrammar c n l t -> [c] -> Input t -> AChart c n l
process strategy mcfg starts toks 
    = trace2 "MCFG.Active - strategy" (if isBU strategy then "BU"
				       else if isTD strategy then "TD" else "None") $
      tracePrt "MCFG.Active - chart size" prtSizes $
      buildChart keyof (complete : combine : convert : rules) axioms
    where rules  | isNil strategy = [scan]
		 | isBU  strategy = [predictKilbury mcfg toks]
		 | isTD  strategy = [predictEarley mcfg toks]
	  axioms | isNil strategy = predict mcfg toks
		 | isBU  strategy = terminal mcfg toks
		 | isTD  strategy = initial mcfg starts toks

isNil s = s=="n"
isBU  s = s=="b"
isTD  s = s=="t"

----------------------------------------------------------------------
-- * type definitions

type AChart c n l = ParseChart (Item c n l) (AKey c) 

data Item   c n l = Active (Abstract c n) 
                           (RangeRec l)  
			   Range 
			   (Lin c l Range) 
			   (LinRec c l Range) 
			   [RangeRec l]
		  | Final (Abstract c n) (RangeRec l) [RangeRec l]
		  | Passive c (RangeRec l)
		     deriving (Eq, Ord, Show)

data AKey       c = Act c
		  | Pass c
		  | Useless
		  | Fin
		    deriving (Eq, Ord, Show)


keyof :: Item c n l -> AKey c
keyof (Active _ _ _ (Lin _ (Cat (next, _, _):_)) _ _) = Act next
keyof (Final _ _ _) = Fin
keyof (Passive cat _) = Pass cat
keyof _ = Useless

-- to be used in prediction
emptyChildren :: Abstract c n -> [RangeRec l]
emptyChildren (Abs _ rhs _) = replicate (length rhs) []

-- for tracing purposes
prtSizes chart = "final=" ++ show (length (chartLookup chart Fin)) ++
		 ", passive=" ++ show (sum [length (chartLookup chart k) | 
					    k@(Pass _) <- chartKeys chart ]) ++
		 ", active=" ++ show (sum [length (chartLookup chart k) | 
					   k@(Act _) <- chartKeys chart ]) ++
		 ", useless=" ++ show (length (chartLookup chart Useless)) 


----------------------------------------------------------------------
-- * inference rules

-- completion
complete :: (Ord c, Ord n, Ord l) => AChart c n l -> Item c n l -> [Item c n l]
complete _ (Active rule found rng (Lin l []) (lin:lins) recs) = 
    return $ Active rule (found ++ [(l, rng)]) EmptyRange lin lins recs 
complete _ _ = []

-- scanning
scan :: (Ord c, Ord n, Ord l) => AChart c n l -> Item c n l -> [Item c n l]
scan _ (Active rule found rng (Lin l (Tok rng':syms)) lins recs) = 
    do rng'' <- concatRange rng rng' 
       return $ Active rule found rng'' (Lin l syms) lins recs 
scan _ _ = []

-- | Creates an Active Item every time it is possible to combine 
-- an Active Item from the agenda with a Passive Item from the Chart 
combine :: (Ord c, Ord n, Ord l) => AChart c n l -> Item c n l -> [Item c n l]
combine chart (Active rule found rng (Lin l (Cat (c, r, d):syms)) lins recs) =
    do Passive _c found' <- chartLookup chart (Pass c)
       rng' <- projection r found'
       rng'' <- concatRange rng rng'
       guard $ subsumes (recs !! d) found' 
       return $ Active rule found rng'' (Lin l syms) lins (replaceRec recs d found') 
combine chart (Passive c found) = 
    do Active rule found' rng' (Lin l ((Cat (_c, r, d)):syms)) lins recs' 
           <- chartLookup chart (Act c)
       rng'' <- projection r found
       rng <- concatRange rng' rng''
       guard $ subsumes (recs' !! d) found
       return $ Active rule found' rng (Lin l syms) lins (replaceRec recs' d found) 
combine _ _ = []      

-- | Active Items with nothing to find are converted to Final items,
-- which in turn are converted to Passive Items
convert :: (Ord c, Ord n, Ord l) => AChart c n l -> Item c n l -> [Item c n l]
convert _ (Active rule found rng (Lin lbl []) [] recs) = 
    return $ Final rule (found ++ [(lbl,rng)]) recs
convert _ (Final (Abs cat _ _) found _) = 
    return $ Passive cat found
convert _ _ = []

----------------------------------------------------------------------
-- Naive --

-- | Creates an Active Item of every Rule in the Grammar to give the initial Agenda
predict :: (Ord c, Ord n, Ord l, Ord t) => MCFGrammar c n l t -> Input t -> [Item c n l]
predict grammar toks = 
    do Rule abs (Cnc _ _ lins) <- grammar
       (lin':lins') <- rangeRestRec toks lins 
       return $ Active abs [] EmptyRange lin' lins' (emptyChildren abs)

----------------------------------------------------------------------
-- Earley --

-- anropas med alla startkategorier
initial :: (Ord c, Ord n, Ord l, Ord t) => MCFGrammar c n l t -> [c] -> Input t -> [Item c n l]
initial mcfg starts toks = 
    do Rule abs@(Abs cat _ _) (Cnc _ _ lins) <- mcfg
       guard $ cat `elem` starts
       lin' : lins' <- rangeRestRec toks lins 
       return $ Active abs [] (Range (0, 0)) lin' lins' (emptyChildren abs)

-- earley prediction
predictEarley :: (Ord c, Ord n, Ord l, Ord t) => MCFGrammar c n l t -> Input t
	      -> AChart c n l -> Item c n l -> [Item c n l]
predictEarley mcfg toks _ (Active _ _ rng (Lin _ (Cat (cat,_,_):_)) _ _) = 
    do rule@(Rule (Abs cat' _ _) _) <- mcfg
       guard $ cat == cat' 
       predEar toks rng rule 
predictEarley _ _ _ _ = []

predEar :: (Ord c, Ord n, Ord l, Ord t) => 
	   Input t -> Range -> MCFRule c n l t -> [Item c n l]
predEar toks _ (Rule abs@(Abs _ [] _) (Cnc _ _ lins)) = 
    do lins' <- rangeRestRec toks lins 
       return $ Final abs (makeRangeRec lins') []
predEar toks rng (Rule abs (Cnc _ _ lins)) =
    do lin' : lins' <- rangeRestRec toks lins 
       return $ Active abs [] (makeMaxRange rng) lin' lins' (emptyChildren abs)

makeMaxRange (Range (_, j)) = Range (j, j)
makeMaxRange EmptyRange     = EmptyRange

----------------------------------------------------------------------
-- Kilbury --

terminal :: (Ord c, Ord n, Ord l, Ord t) => MCFGrammar c n l t -> Input t -> [Item c n l]
terminal mcfg toks = 
    do Rule abs@(Abs _ [] _) (Cnc _ _ lins) <- mcfg
       lins' <- rangeRestRec toks lins 
       return $ Final abs (makeRangeRec lins') []

-- kilbury prediction
predictKilbury :: (Ord c, Ord n, Ord l, Ord t) => 
		  MCFGrammar c n l t -> Input t
	       -> AChart c n l -> Item c n l -> [Item c n l]
predictKilbury mcfg toks _ (Passive cat found) = 
    do Rule abs@(Abs _ rhs _) (Cnc _ _ (Lin l (Cat (cat', r, i):syms) : lins)) <- mcfg
       guard $ cat == cat'
       lin' : lins' <- rangeRestRec toks (Lin l syms : lins)
       rng <- projection r found
       let children = replaceRec (emptyChildren abs) i found 
       return $ Active abs [] rng lin' lins' children
predictKilbury _ _ _ _ = []