You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
br-parser-tools/collects/mrspidey/Sba/min/min-dfa.ss

491 lines
17 KiB
Scheme

; ======================================================================
; minimize-constraints-dfa-min-fast
;
; Input: lower : list Tvar
; upper : list Tvar
;
; see practical.tex
; ======================================================================
; ----------------------------------------------------------------------
; Copyright (C) 1995-97 Cormac Flanagan
;
; This program is free software; you can redistribute it and/or
; modify it under the terms of the GNU General Public License
; version 2 as published by the Free Software Foundation.
;
; 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.
; ----------------------------------------------------------------------
(define (minimize-constraints-dfa-min-fast
lower upper
helper-fn)
(pretty-debug-dfa-min
`(minimize-constraints-dfa-min-fast
lower ,(map Tvar-name lower)
upper ,(map Tvar-name upper)))
(let*-vals
([t (lambda (s)
(when timing-min
(min-record-progress
(cons 'minimize-constraints-dfa-min-fast s))))]
[_ (t 0)]
[(live-tvars live-tvar? live-nts tvar->equiv AV->equiv)
((copy-live-constraints-few-e #t #t) lower upper)]
[_ (t 1)]
;; Figure out representative elements for Tvars,
;; and live AV
[(tvar->rep set-tvar-rep!) (alloc-Tvar-field)]
[(is-rep? add-rep! get-list-rep) (field->set alloc-Tvar-field)]
[(live-AV? set-live-AV! get-live-AVs) (field->set alloc-AV-field)]
[_ (for-each
(lambda (tvar)
(for-each set-live-AV! (get-Tvar-objs tvar))
(unless (tvar->rep tvar)
(add-rep! tvar)
(for-each
(lambda (eq) (set-tvar-rep! eq tvar))
(tvar->equiv tvar))
(assert (tvar->rep tvar))))
live-tvars)]
[live-AVs (get-live-AVs)]
[rep-tvars (get-list-rep)]
[_ (t 2)]
;; states = rep-tvars + live-AVs + dummy-tvar
[dummy-tvar (mk-Tvar 'Grammar-dummy)]
[all-states (append rep-tvars (list dummy-tvar) live-AVs)]
[state->sym (lambda (state)
(cond
[(Tvar? state) (Tvar-name state)]
[(AV? state) (AV->rep state)]
[else (error 'state->sym "Bad state ~s" state)]))]
[grsym-eq?
(lambda (g1 g2)
;; (andmap eq? g1 g2)
(recur loop ([g1 g1][g2 g2])
(if (null? g1)
(null? g2)
(if (null? g2)
#f
(and (eq? (car g1) (car g2))
(loop (cdr g1) (cdr g2)))))))]
;; mapping from grsyms to numbers
[num-grsym 0]
[grsym-table '()]
[grsym->number
(lambda (g1)
(or
(ormap
(match-lambda
[(n . g2) (and (grsym-eq? g1 g2) n)]
[_ #f])
grsym-table)
(begin
(set! grsym-table (cons (cons num-grsym g1) grsym-table))
(begin0
num-grsym
(set! num-grsym (add1 num-grsym))))))]
[(tvar-EF-epsilon set-tvar-EF-epsilon!)
(alloc-Tvar-field (lambda () '()))]
[(tvar-EF set-tvar-EF!)
(alloc-Tvar-field (lambda () '()))]
[(AV-EF-epsilon set-AV-EF-epsilon!)
(alloc-AV-field (lambda () '()))]
[(AV-EF set-AV-EF!)
(alloc-AV-field (lambda () '()))]
[add-tvar-EF!
(lambda (tvar g1 s1)
(let* ( [tvar (tvar->rep tvar)]
[n1 (grsym->number g1)]
[x (tvar-EF tvar)])
(unless (ormap
(match-lambda [(n2 . s2) (and (= n1 n2) (eq? s1 s2))])
x)
(set-tvar-EF! tvar (cons (cons n1 s1) x)))))]
[add-AV-EF!
(lambda (AV g1 s1)
(let ( [x (AV-EF AV)]
[n1 (grsym->number g1)])
(unless (ormap
(match-lambda [(n2 . s2) (and (= n1 n1) (eq? s1 s2))])
x)
(set-AV-EF! AV (cons (cons n1 s1) x)))))]
[add-tvar-EF-epsilon!
(lambda (tvar s1)
(let* ( [tvar (tvar->rep tvar)]
[x (tvar-EF-epsilon tvar)])
(unless (memq s1 x)
(set-tvar-EF-epsilon! tvar (cons s1 x)))))]
[add-AV-EF-epsilon!
(lambda (AV s1)
(let ([x (AV-EF-epsilon AV)])
(unless (memq s1 x)
(set-AV-EF-epsilon! AV (cons s1 x)))))]
[state-EF-epsilon
(lambda (state)
(if (AV? state)
(AV-EF-epsilon state)
(tvar-EF-epsilon state)))]
[state-EF
(lambda (state)
(if (AV? state)
(AV-EF state)
(tvar-EF state)))]
[_ (t 2.1)]
;; helper-fn sets things up for inv-delta-traversal
;; Sets U field of each state to:
;; (listof (cons (listof any) state))
[extra-seperate (helper-fn live-tvars live-tvar? tvar->rep live-AVs
add-tvar-EF! add-tvar-EF-epsilon!
add-AV-EF! add-AV-EF-epsilon!)]
[_ (t 3)]
;; Show productions
[_ (pretty-debug-dfa-min
`(productions
,(map
(lambda (state)
(list (state->sym state)
(map state->sym (state-EF-epsilon state))
(map
(match-lambda [(g . s) (cons g (state->sym s))])
(state-EF state))))
all-states)))]
;; Vector of buckets for productions
[buckets (make-vector num-grsym '())]
[_ (min-record-progress (cons 'num-buckets num-grsym))]
;; inv-delta-traversal:
;; P(states) x (P(states) -> void) -> void
;; inv-delta-traversal(X, split)
;; => no equiv class partially in X
;; => Call split with each "partition of equiv classes" ...
;; For effeciency, we call split with a "generator" for the set C_a
;; The generator is passed a function add-split!, and then
;; calls add-split! on each state in C_a
;; --- Set things up for Hopcrofts Algorithm
;; Condition 1, thms hopcroft lub and glb
;; Also, to make up for grammar being "incomplete",
;; seperate states into equiv classes so states in same equiv class
;; have productions on same grammar symbols
[seperate-grsyms (make-vector num-grsym '())]
[seperate-epsilon '()]
[_ (for-each
(lambda (state)
(when (not (null? (state-EF-epsilon state)))
(set! seperate-epsilon (cons state seperate-epsilon)))
(for-each
(match-lambda
[(g . s)
(vector-set! seperate-grsyms g
(cons s (vector-ref seperate-grsyms g)))])
(state-EF state)))
all-states)]
[_ (pretty-debug-dfa-min
`(seperate-epsilon ,(map state->sym seperate-epsilon)))]
[_ (pretty-debug-dfa-min
`(seperate-grsyms
,(map
(lambda (s) (map state->sym s))
(vector->list seperate-grsyms))))]
[seperate (append
(list rep-tvars)
(list live-AVs)
extra-seperate
;(map list lower)
;(map list upper)
(list seperate-epsilon)
(vector->list seperate-grsyms))]
[seperate (filter
(lambda (l) (not (null? l)))
seperate)]
[_ (pretty-debug-dfa-min
`(seperate ,(map (lambda (s) (map state->sym s)) seperate)))]
[_ (t 4)]
[inv-delta-traversal
(lambda (states split)
(pretty-debug-dfa-min
`(inv-delta-trav
,(map (lambda (state)
`(,(state->sym state)
(epsilon
,(map state->sym (state-EF-epsilon state)))
,(map
(match-lambda [(g . s) (cons g (state->sym s))])
(state-EF state))))
states)))
;; Do epsilons
(split
(lambda (add-split!)
(for-each
(lambda (state)
(for-each
add-split!
(state-EF-epsilon state)))
states)))
;; Put rest into buckets
(let ([bucket-ndxs '()])
(for-each
(lambda (state)
(for-each
(match-lambda
[(n . s)
(let ([old (vector-ref buckets n)])
(vector-set! buckets n (cons s old))
(when (null? old)
(set! bucket-ndxs (cons n bucket-ndxs))))])
(state-EF state)))
states)
;; Run thru buckets ...
(for-each
(lambda (i)
(let ([s* (vector-ref buckets i)])
(split (lambda (add-split!) (for-each add-split! s*)))
(vector-set! buckets i '())))
bucket-ndxs)))]
[(state-aux set-state-aux!) (alloc-NT-field)]
[(state->rep state->equiv equiv-state? list-rep-states)
(Hopcroft-calc-equivalences
all-states
seperate
inv-delta-traversal
state-aux set-state-aux! state->sym)]
[_ (t 5)]
[_ (begin
(pretty-debug-dfa-min
`(list-rep-state ,(map state->sym list-rep-states)))
(pretty-debug-dfa-min
`(state->equiv
,(map (lambda (state)
(map state->sym (state->equiv state)))
list-rep-states))))]
;; ----------------------------------------
;; Have equivalence relation on states
;; Combine w/ previous relation on Tvars
;; Convert to equivalence relation on Tvars
[tvar->equiv
(lambda (tvar)
(let ([r (apply append (map tvar->equiv (state->equiv tvar)))])
(pretty-debug-dfa-min
`(tvar->equiv ,(state->sym tvar) = ,(map state->sym r)))
r))]
[AV->equiv
(lambda (x)
(pretty-debug-dfa-min `(AV->equiv ,(state->sym x)))
(let ([e (state->equiv x)])
(pretty-debug-dfa-min
`(AV->equiv ,(state->sym x) = ,(map state->sym e)))
e))]
[_ (t 6)])
(copy-constraints-equiv!
live-tvars
live-tvar?
live-nts
tvar->equiv
AV->equiv)))
;; ======================================================================
(define (minimize-constraints-dfa-min-lub lower upper)
(minimize-constraints-dfa-min-fast lower upper
;; helper-fn
;; helper-fn sets things up for inv-delta-traversal
;; Sets U field of each state to:
;; (listof (cons (listof any) state))
(lambda (live-tvars live-tvar? tvar->rep live-AVs
add-tvar-EF! add-tvar-EF-epsilon!
add-AV-EF! add-AV-EF-epsilon!)
(for-each
(lambda (tvar)
;; --- Condition 2
;; If [a <= b] => forall a'~a exists b'~b st [a' <= b']
(for-each
(lambda (from)
(when (live-tvar? from)
(add-tvar-EF-epsilon! tvar (tvar->rep from))))
(Tvar-edgefrom tvar))
(for-each
(lambda (AV) (add-tvar-EF-epsilon! tvar AV))
(get-Tvar-objs tvar))
;; --- Conditions 4 and 5
(for-each
(match-lambda
[($ con _ template field alpha sign)
(when (live-tvar? alpha)
(if sign
;; [rng(tvar) <= alpha]
(add-tvar-EF! alpha
(list 'R4 template field) (tvar->rep tvar))
(when #t ;; (follow-antimono-fields template)
;; Condition 5
;; At bottom we put beta (or tvar) in own equiv class
;; [alpha <= dom(tvar)]
(add-tvar-EF! tvar
(list 'R5 template field) (tvar->rep alpha)))))]
[_ (void)])
(Tvar-constraints tvar)))
live-tvars)
(for-each
(match-lambda
[(and AV ($ AV _ template _ fields+ fields-))
;; --- Condition 3
(for i 0 (vector-length fields+)
(let ([field (vector-ref fields+ i)])
(when (live-tvar? field)
(add-AV-EF! AV
(list 'R3 template i) (tvar->rep field)))))])
live-AVs)
;; extra partitions
(append
;; Put each beta st [alpha <= dom(beta)] in separate equiv class
(map list
(map tvar->rep
(filter
(lambda (tvar)
(ormap
(match-lambda
[($ con _ template field alpha #f)
(live-tvar? alpha)]
[_ #f])
(Tvar-constraints tvar)))
live-tvars)))
;; put AVs into equiv class according to templates
;; h maps templates to list of AVs
(let ([h (make-hash-table)])
(for-each
(lambda (AV)
(let ([t (AV-template AV)])
(hash-table-put! h t
(cons AV (hash-table-get h t (lambda () ()))))))
live-AVs)
(hash-table-map h
(lambda (t AVs) AVs))))
)))
;; ======================================================================
(define (minimize-constraints-dfa-min-glb lower upper)
(minimize-constraints-dfa-min-fast lower upper
;; helper-fn
;; helper-fn sets things up for inv-delta-traversal
;; Sets U field of each state to:
;; (listof (cons (listof any) state))
(lambda (live-tvars live-tvar? tvar->rep live-AVs
add-tvar-EF! add-tvar-EF-epsilon!
add-AV-EF! add-AV-EF-epsilon!)
(for-each
(lambda (tvar)
;; --- Condition 2
;; If [a <= b] => forall b'~b exists a'~a st [a' <= b']
(for-each
(lambda (from)
(when (live-tvar? from)
(add-tvar-EF-epsilon! from (tvar->rep tvar))))
(Tvar-edgefrom tvar))
(for-each
(lambda (AV) (add-AV-EF-epsilon! AV (tvar->rep tvar)))
(get-Tvar-objs tvar))
;; --- Condition 4
(for-each
(match-lambda
[($ con _ template field alpha #t)
(when (live-tvar? alpha)
;; [rng(tvar) <= alpha]
(add-tvar-EF! tvar
(list 'R4 template field) (tvar->rep alpha)))]
[_ (void)])
(Tvar-constraints tvar)))
live-tvars)
(for-each
(match-lambda
[(and AV ($ AV _ template _ fields+ fields-))
;; --- Condition 3
(for i 0 (vector-length fields+)
(let ([field (vector-ref fields+ i)])
(when (live-tvar? field)
(add-tvar-EF! field (list 'R3 template i) AV))))
;; --- Condition 5
(when (follow-antimono-fields template)
(for i 0 (vector-length fields-)
(let ([field (vector-ref fields- i)])
(when (live-tvar? field)
;; [dom(AV) <= field]
;; At bottom we put AV in own equiv class
(add-AV-EF! AV
(list 'R5 template i) (tvar->rep field))))))])
live-AVs)
;; Conditions 5,6, thm 1.2
;; extra partitioning
(append
;; Conditions 5, thm 1.2
(filter-map
(match-lambda
[(and AV ($ AV _ template _ _ fields-))
(and
(follow-antimono-fields template)
(> (vector-length fields-) 0)
(list AV))])
live-AVs)
;; Conditions 6, thm 1.2
(let ([h (make-hash-table)])
(for-each
(match-lambda
[(and AV ($ AV _ template))
(hash-table-put! h template
(cons AV
(hash-table-get h template (lambda () '()))))])
live-AVs)
(hash-table-map h
(lambda (template AVs) AVs)))))))
;; ======================================================================