|
50 | 50 | ;; rhs sort
|
51 | 51 | (define sorted-right
|
52 | 52 | (sort-productions cyclic
|
53 |
| - cyclic-nts |
54 | 53 | clang-all-ht/f))
|
55 | 54 |
|
56 | 55 | (values sorted-left
|
|
105 | 104 | (hash)
|
106 | 105 | lang))
|
107 | 106 |
|
108 |
| -;; find-cycles : (hash[symbol] -o> (setof symbol)) -> (setof symbol) |
| 107 | +;; find-cycles : (hash[symbol -o> (setof symbol)]) -> (setof symbol) |
109 | 108 | (define (find-cycles edges)
|
110 | 109 | (foldl
|
111 | 110 | (λ (v s)
|
|
190 | 189 | lang))
|
191 | 190 |
|
192 | 191 |
|
193 |
| -;; sort-productions : lang, |
194 |
| -;; (hash[symbol] -o> (setof symbol)) |
195 |
| -;; (or/c #f (hash[symbol -o> (list/c any)])) -> lang |
196 |
| -(define (sort-productions cyclic nts clang-all-ht/f) |
197 |
| - (define table (terminal-distance-table cyclic nts)) |
198 |
| - (for/list ([cur-nt (in-list cyclic)]) |
| 192 | +;; Problem: we need to find an ordering of the productions of each of |
| 193 | +;; the metavariables such that the graph induced by the first |
| 194 | +;; productions in each case has no cycles. |
| 195 | +;; |
| 196 | +;; We use a fairly simple algorithm. We start with an empty set of |
| 197 | +;; sinks. An out-edge is an edge all of whose targets are sinks |
| 198 | +;; (note that this includes the empty set). |
| 199 | +;; |
| 200 | +;; Go through each vertex. If it contains an out-edge, pick it, and |
| 201 | +;; add the vertex to the list of sinks. Repeat until all vertices |
| 202 | +;; are sinks. |
| 203 | +;; |
| 204 | +;; For now, diverges if it's impossible :(. |
| 205 | +;; To fix: if a round completes without any vertices becoming a |
| 206 | +;; sink the jig is up |
| 207 | + |
| 208 | +(define (spanning-tree hg) |
| 209 | + (let loop ([hg hg] |
| 210 | + [sinks (set)] |
| 211 | + [edges (hash)] |
| 212 | + [vertices (hash-keys hg)]) |
| 213 | + (match vertices |
| 214 | + ['() edges] |
| 215 | + [(cons v vs) |
| 216 | + (define good-edge |
| 217 | + (findf (λ (e) (andmap (λ (v) (set-member? sinks v)) (set->list (second e)))) |
| 218 | + (hash-ref hg v))) |
| 219 | + (cond [good-edge |
| 220 | + (loop hg |
| 221 | + (set-add sinks v) |
| 222 | + (hash-set edges v good-edge) |
| 223 | + vs)] |
| 224 | + [else |
| 225 | + (loop hg sinks edges (append vs (list v)))])]))) |
| 226 | + |
| 227 | +;; A HyperGraph is a Hash NTName (Listof (List Index (Setof NTName))) |
| 228 | +;; associating each non-terminal to a list of out-going edges |
| 229 | +(define (hypergraph lang) |
| 230 | + (for/hash ([nt (in-list lang)]) |
| 231 | + (define out-edges |
| 232 | + (for/list ([i (in-naturals)] |
| 233 | + [rhs (in-list (nt-rhs nt))]) |
| 234 | + (list i (directly-used-nts (rhs-pattern rhs))))) |
| 235 | + (values (nt-name nt) out-edges))) |
| 236 | + |
| 237 | +;; sort-productions : lang (or/c #f (hash[symbol -o> (list/c any)])) |
| 238 | +;; -> lang |
| 239 | +;; sorts the language |
| 240 | +;; SIDE EFFECT: if clang-all-ht/f is not #f, sorts it |
| 241 | +(define (sort-productions lang clang-all-ht/f) |
| 242 | + (define spanner (spanning-tree (hypergraph lang))) |
| 243 | + (for/list ([cur-nt (in-list lang)]) |
199 | 244 | (match cur-nt
|
200 | 245 | [(nt name productions)
|
201 |
| - (define (max-terminal-distance pat) |
202 |
| - (define referenced-nts (directly-used-nts pat)) |
203 |
| - (define maximum |
204 |
| - (for/max ([cur-name (in-set referenced-nts)]) |
205 |
| - (if (symbol=? cur-name name) |
206 |
| - +inf.0 |
207 |
| - (hash-ref table cur-name 0)))) |
208 |
| - (if (and (negative? maximum) |
209 |
| - (infinite? maximum)) |
210 |
| - 0 |
211 |
| - maximum)) |
| 246 | + (define the-edge (first (hash-ref spanner name))) |
| 247 | + |
| 248 | + ;; less than if the left is the chosen one and the right is not |
| 249 | + (define (less-than? i1 i2) |
| 250 | + (and (equal? i1 the-edge) |
| 251 | + (not (equal? i2 the-edge)))) |
| 252 | + |
212 | 253 | (define production-vec (apply vector productions))
|
213 | 254 | (define permutation
|
214 | 255 | (sort (build-list (vector-length production-vec) values)
|
215 |
| - < |
216 |
| - #:key (compose max-terminal-distance |
217 |
| - rhs-pattern |
218 |
| - (λ (i) (vector-ref production-vec i))) |
| 256 | + less-than? |
219 | 257 | #:cache-keys? #t))
|
220 | 258 | (when clang-all-ht/f
|
221 | 259 | (define clang-all-ht-nt-vec (apply vector (hash-ref clang-all-ht/f name)))
|
|
226 | 264 | (for/list ([i (in-list permutation)])
|
227 | 265 | (vector-ref production-vec i)))])))
|
228 | 266 |
|
229 |
| -;; terminal-distance-table : lang (hash[symbol] -o> symbol) |
230 |
| -;; -> (hash[symbol] -o> (U natural +inf) |
231 |
| -(define (terminal-distance-table cyclic recs) |
232 |
| - (define (terminal-distance pat this-nt-name table) |
233 |
| - (define referenced-nts (directly-used-nts pat)) |
234 |
| - (define maximum |
235 |
| - (for/max ([cur-name (in-set referenced-nts)]) |
236 |
| - (cond [(symbol=? cur-name this-nt-name) |
237 |
| - +inf.0] |
238 |
| - [else |
239 |
| - (hash-ref table cur-name 0)]))) |
240 |
| - (or (and (infinite? maximum) |
241 |
| - (negative? maximum) |
242 |
| - 0) |
243 |
| - (add1 maximum))) |
244 |
| - (build-nt-property/name cyclic |
245 |
| - terminal-distance |
246 |
| - +inf.0 |
247 |
| - min)) |
| 267 | +;; A NTName is a symbol representing the name of a non-terminal |
248 | 268 |
|
249 | 269 | ;; directly-used-nts : pat -> (setof symbol)
|
250 | 270 | (define (directly-used-nts pat)
|
|
0 commit comments