Skip to content

Commit cd2b520

Browse files
committed
extend enum sorting to handle unsolvable cases
1 parent 57ceaa9 commit cd2b520

File tree

1 file changed

+50
-57
lines changed

1 file changed

+50
-57
lines changed

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

Lines changed: 50 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
racket/match
99
racket/set
1010
racket/promise
11-
"build-nt-property.rkt"
1211
"lang-struct.rkt"
1312
"match-a-pattern.rkt")
1413

@@ -44,17 +43,15 @@
4443
(set-member? cyclic-nts (nt-name nt)))
4544
lang))
4645
;; topological sort
47-
(define sorted-left
46+
(define sorted-finite
4847
(topo-sort non-cyclic
4948
(filter-edges edges non-cyclic)))
5049
;; rhs sort
51-
(define sorted-right
52-
(sort-productions cyclic
53-
clang-all-ht/f))
54-
55-
(values sorted-left
56-
sorted-right
57-
(build-cant-enumerate-table lang edges)))
50+
(define-values (sorted-cyclic unsolvables)
51+
(sort-productions cyclic clang-all-ht/f))
52+
(values sorted-finite
53+
sorted-cyclic
54+
(build-cant-enumerate-table lang edges unsolvables)))
5855

5956
;; find-edges : lang -> (hash[symbol] -o> (setof (listof symbol)))
6057
(define (find-edges lang)
@@ -192,37 +189,28 @@
192189
;; Problem: we need to find an ordering of the productions of each of
193190
;; the metavariables such that the graph induced by the first
194191
;; 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-
192+
;; spanning-tree : HyperGraph -> (Listof (List Index (Setof NTName))) (Listof NTName)
208193
(define (spanning-tree hg)
209-
(let loop ([hg hg]
210-
[sinks (set)]
194+
(define init-vertices (hash-keys hg))
195+
(let loop ([sinks (set)]
211196
[edges (hash)]
212-
[vertices (hash-keys hg)])
213-
(match vertices
214-
['() edges]
215-
[(cons v vs)
197+
[vertices init-vertices]
198+
[time (length init-vertices)])
199+
(cond
200+
[(zero? time)
201+
(values edges vertices)]
202+
[else
203+
(match-define (cons v vs) vertices)
216204
(define good-edge
217205
(findf (λ (e) (andmap (λ (v) (set-member? sinks v)) (set->list (second e))))
218206
(hash-ref hg v)))
219207
(cond [good-edge
220-
(loop hg
221-
(set-add sinks v)
208+
(loop (set-add sinks v)
222209
(hash-set edges v good-edge)
223-
vs)]
210+
vs
211+
(sub1 time))]
224212
[else
225-
(loop hg sinks edges (append vs (list v)))])])))
213+
(loop sinks edges (append vs (list v)) (sub1 time))])])))
226214

227215
;; A HyperGraph is a Hash NTName (Listof (List Index (Setof NTName)))
228216
;; associating each non-terminal to a list of out-going edges
@@ -239,30 +227,35 @@
239227
;; sorts the language
240228
;; SIDE EFFECT: if clang-all-ht/f is not #f, sorts it
241229
(define (sort-productions lang clang-all-ht/f)
242-
(define spanner (spanning-tree (hypergraph lang)))
243-
(for/list ([cur-nt (in-list lang)])
244-
(match cur-nt
245-
[(nt name productions)
246-
(define the-edge (first (hash-ref spanner name)))
230+
(define-values (spanner unsolvables) (spanning-tree (hypergraph lang)))
231+
(define sorted
232+
(for/list ([cur-nt (in-list lang)])
233+
(match cur-nt
234+
[(nt name productions)
235+
(cond
236+
[(hash-has-key? spanner name)
237+
(define the-edge (first (hash-ref spanner name)))
247238

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))))
239+
;; less than if the left is the chosen one and the right is not
240+
(define (less-than? i1 i2)
241+
(and (equal? i1 the-edge)
242+
(not (equal? i2 the-edge))))
252243

253-
(define production-vec (apply vector productions))
254-
(define permutation
255-
(sort (build-list (vector-length production-vec) values)
256-
less-than?
257-
#:cache-keys? #t))
258-
(when clang-all-ht/f
259-
(define clang-all-ht-nt-vec (apply vector (hash-ref clang-all-ht/f name)))
260-
(hash-set! clang-all-ht/f name
261-
(for/list ([i (in-list permutation)])
262-
(vector-ref clang-all-ht-nt-vec i))))
263-
(nt name
264-
(for/list ([i (in-list permutation)])
265-
(vector-ref production-vec i)))])))
244+
(define production-vec (apply vector productions))
245+
(define permutation
246+
(sort (build-list (vector-length production-vec) values)
247+
less-than?
248+
#:cache-keys? #t))
249+
(when clang-all-ht/f
250+
(define clang-all-ht-nt-vec (apply vector (hash-ref clang-all-ht/f name)))
251+
(hash-set! clang-all-ht/f name
252+
(for/list ([i (in-list permutation)])
253+
(vector-ref clang-all-ht-nt-vec i))))
254+
(nt name
255+
(for/list ([i (in-list permutation)])
256+
(vector-ref production-vec i)))]
257+
[else (nt name productions)])])))
258+
(values sorted unsolvables))
266259

267260
;; A NTName is a symbol representing the name of a non-terminal
268261

@@ -367,8 +360,7 @@
367360
(my-max current-max
368361
(let () . defs+exprs))))]))
369362

370-
371-
(define (build-cant-enumerate-table lang edges)
363+
(define (build-cant-enumerate-table lang edges unsolvables)
372364
;; cant-enumerate-table : hash[sym[nt] -o> boolean]
373365
(define cant-enumerate-table (make-hash))
374366

@@ -401,7 +393,8 @@
401393
;; fill in the entire table
402394
(for ([nt (in-list lang)])
403395
(cant-enumerate-nt/fill-table (nt-name nt)))
404-
396+
(for ([name (in-list unsolvables)])
397+
(hash-set! cant-enumerate-table name #t))
405398
cant-enumerate-table)
406399

407400
;; can-enumerate? : any/c hash[sym -o> any[boolean]] (promise hash[sym -o> any[boolean]])

0 commit comments

Comments
 (0)