Skip to content

Commit 57ceaa9

Browse files
committed
when enumerating, always put a productive production first*
*currently loops when this is impossible
1 parent 32a2744 commit 57ceaa9

File tree

1 file changed

+62
-42
lines changed

1 file changed

+62
-42
lines changed

redex-lib/redex/private/preprocess-lang.rkt

Lines changed: 62 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@
5050
;; rhs sort
5151
(define sorted-right
5252
(sort-productions cyclic
53-
cyclic-nts
5453
clang-all-ht/f))
5554

5655
(values sorted-left
@@ -105,7 +104,7 @@
105104
(hash)
106105
lang))
107106

108-
;; find-cycles : (hash[symbol] -o> (setof symbol)) -> (setof symbol)
107+
;; find-cycles : (hash[symbol -o> (setof symbol)]) -> (setof symbol)
109108
(define (find-cycles edges)
110109
(foldl
111110
(λ (v s)
@@ -190,32 +189,71 @@
190189
lang))
191190

192191

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)])
199244
(match cur-nt
200245
[(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+
212253
(define production-vec (apply vector productions))
213254
(define permutation
214255
(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?
219257
#:cache-keys? #t))
220258
(when clang-all-ht/f
221259
(define clang-all-ht-nt-vec (apply vector (hash-ref clang-all-ht/f name)))
@@ -226,25 +264,7 @@
226264
(for/list ([i (in-list permutation)])
227265
(vector-ref production-vec i)))])))
228266

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
248268

249269
;; directly-used-nts : pat -> (setof symbol)
250270
(define (directly-used-nts pat)

0 commit comments

Comments
 (0)