|
17 | 17 | (dfa-intersection dfaA dfaB) |
18 | 18 | (dfa-less dfaA dfaB) |
19 | 19 | (dfa-states dfaA) |
| 20 | + (dfa-minimize! dfaA) |
20 | 21 | (dfa-remove-unreachable-states! dfaA) |
21 | 22 | (dfa-rename-states dfaA) |
22 | 23 | test-dfa |
|
72 | 73 | (else |
73 | 74 | (%run-dfa next-state dfa (cdr input)))))))) |
74 | 75 |
|
| 76 | +;; Convert a dfa to an nfa, this doesn't really have to do anything |
| 77 | +;; except make a new nfa record. |
75 | 78 | (define (dfa->nfa dfaA) |
76 | 79 | (nfa (dfa-alphabet dfaA) |
77 | 80 | (dfa-states dfaA) |
|
85 | 88 | (let* ((nfaC (apply nfa-concat (map dfa->nfa (cons dfaA (cons dfaB rest)))))) |
86 | 89 | (nfa->dfa nfaC))) |
87 | 90 |
|
88 | | -;; ;; Concatenate two dfas. |
89 | | -;; ;; The start state of B becomes the final state of dfaA. |
90 | | -;; ;; Replace each reference to the start state of dfaB |
91 | | -;; ;; with a references to the final states of dfaA. |
92 | | -;; (define (dfa-concat dfaA dfaB) |
93 | | -;; (let* ((qfinal-A (dfa-final-states dfaA)) |
94 | | -;; (qfinal-B (dfa-final-states dfaB)) |
95 | | -;; (q0-B (dfa-start-state dfaB)) |
96 | | -;; (new-start (dfa-start-state dfaA)) |
97 | | -;; (new-final (if (member q0-B qfinal-B) |
98 | | -;; ;; replace q0-B with the set qfinal-A |
99 | | -;; (append (remq q0-B qfinal-B) |
100 | | -;; qfinal-A) |
101 | | -;; qfinal-B)) |
102 | | -;; (new-trans-B (flatten |
103 | | -;; (map (lambda (qfinal) |
104 | | -;; (map (lambda (trans) |
105 | | -;; (let ((qA (if (equal? (first trans) q0-B) |
106 | | -;; qfinal (first trans))) |
107 | | -;; (qB (if (equal? (third trans) q0-B) |
108 | | -;; qfinal (third trans)))) |
109 | | -;; (list qA (second trans) qB))) |
110 | | -;; (dfa-transition-list dfaB))) |
111 | | -;; qfinal-A))) |
112 | | -;; (new-trans (append (dfa-transition-list dfaA) new-trans-B)) |
113 | | -;; (new-alphabet (union (dfa-alphabet dfaA) (dfa-alphabet dfaB)))) |
114 | | -;; (print new-trans) |
115 | | -;; ; (dfa-rename-states |
116 | | -;; (dfa |
117 | | -;; new-start |
118 | | -;; new-trans |
119 | | -;; new-final |
120 | | -;; new-alphabet))) |
121 | | - |
122 | 91 | ;; A complete dfa has transitions out of every state for every symbol |
123 | 92 | ;; in the language. |
124 | 93 | ;; This will add in the necessary extra transitions, which will go |
125 | 94 | ;; to a new sink state |
126 | 95 | (define (dfa-complete dfaA) |
127 | 96 | (define transitions (dfa-transition-list dfaA)) |
128 | 97 | (define sink-state (gensym "sink")) |
129 | | - (let loop0 ((states (cons sink-state |
130 | | - (nub (append |
131 | | - (map first (dfa-transition-list dfaA)) |
132 | | - (map third (dfa-transition-list dfaA))))))) |
133 | | -; (print states) |
134 | | - (cond ((not (null? states)) |
135 | | - (let loop1 ((alphabet (dfa-alphabet dfaA))) |
136 | | - ;(print alphabet) |
137 | | - (cond ((not (null? alphabet)) |
138 | | - ; (print (car states) " " (car alphabet) " " |
139 | | - ; ((dfa-transition dfaA) (car states) (car alphabet))) |
140 | | - (if (equal? (dfa-trans dfaA (car states) (car alphabet)) #f) |
141 | | - ; There is no transition for this state and symbol |
142 | | - ; So add a transition to the sink state |
143 | | - (set! transitions |
144 | | - (cons (list (car states) |
145 | | - (car alphabet) |
146 | | - sink-state) |
147 | | - transitions))) |
148 | | - (loop1 (cdr alphabet))))) |
149 | | - (loop0 (cdr states))) |
150 | | - (else |
151 | | - (dfa-rename-states |
152 | | - (dfa (dfa-start-state dfaA) |
153 | | - transitions |
154 | | - (dfa-final-states dfaA) |
155 | | - (dfa-alphabet dfaA))))))) |
| 98 | + ;; Check if is complete beforehand |
| 99 | + (cond ((is-complete? dfaA) dfaA) |
| 100 | + (else (map (lambda (state) |
| 101 | + (map (lambda (symbol) |
| 102 | + (if (equal? (dfa-trans dfaA state symbol) #f) |
| 103 | + ;; Add a transition to the sink state |
| 104 | + (set! transitions |
| 105 | + (cons (list state symbol sink-state) |
| 106 | + transitions)))) |
| 107 | + (dfa-alphabet dfaA))) |
| 108 | + (cons sink-state (dfa-states dfaA))) |
| 109 | + (dfa-rename-states |
| 110 | + (dfa (dfa-start-state dfaA) |
| 111 | + transitions |
| 112 | + (dfa-final-states dfaA) |
| 113 | + (dfa-alphabet dfaA)))))) |
| 114 | + |
| 115 | +(define (is-complete? dfaA) |
| 116 | + (let loop ((states (dfa-states dfaA)) |
| 117 | + (alphabet (dfa-alphabet dfaA))) |
| 118 | + (cond ((null? states) #t) |
| 119 | + ((null? alphabet) (loop (cdr states) (dfa-alphabet dfaA))) |
| 120 | + ((equal? #f (dfa-trans dfaA (car states) (car alphabet))) #f) |
| 121 | + (else (loop states (cdr alphabet)))))) |
156 | 122 |
|
| 123 | +;; Returns the dfa for the universal language, eg. E* |
157 | 124 | (define (dfa-universal alphabet) |
158 | 125 | (let* ((q0 (gensym "q")) |
159 | 126 | (trans (map |
|
183 | 150 | new-final |
184 | 151 | (dfa-alphabet cdfa))))) |
185 | 152 |
|
| 153 | + |
| 154 | +(define (dfa-less dfa1 dfa2) |
| 155 | + (dfa-intersection dfa1 (dfa-complement dfa2))) |
| 156 | +;; (let* ((i (dfa-complement dfa2)) |
| 157 | +;; (l (dfa-intersection dfa1 i))) |
| 158 | +;; (print "inv")(read) |
| 159 | +;; (show-graph (graph i)) |
| 160 | +;; (print "dfa1")(read) |
| 161 | +;; (show-graph (graph dfa1)) |
| 162 | +;; (print "intersection")(read) |
| 163 | +;; (show-graph (graph l)) |
| 164 | +;; l)) |
| 165 | + |
| 166 | + |
186 | 167 | ;; Returns a dfa that is the intersection of dfaA and dfaB |
187 | 168 | (define (dfa-intersection dfaA dfaB) |
188 | | - (print-dfa dfaA) |
189 | | - (print-dfa dfaB) |
| 169 | +; (print-dfa dfaA) |
| 170 | +; (print-dfa dfaB) |
190 | 171 | (let* ((alphabet (union (dfa-alphabet dfaA) |
191 | 172 | (dfa-alphabet dfaB))) |
192 | 173 | (new-start (list (dfa-start-state dfaA) |
|
237 | 218 | (else |
238 | 219 | new-transitions)))) |
239 | 220 |
|
| 221 | +(define (dfa-minimize! dfa1) |
| 222 | + (dfa-remove-unreachable-states! dfa1) |
| 223 | + (%dfa-minimize! dfa1)) |
| 224 | + |
| 225 | +;; Minimise a dfa |
| 226 | +;; Find the states that are equivalent and merge them |
| 227 | +(define (%dfa-minimize! dfa1) |
| 228 | + (let loop0 ((states1 (dfa-states dfa1))) |
| 229 | + (if (not (null? states1)) |
| 230 | + (let loop1 ((states2 (dfa-states dfa1))) |
| 231 | + (if (not (null? states2)) |
| 232 | + (let ((state1 (car states1)) |
| 233 | + (state2 (car states2))) |
| 234 | + (if (and (not (equal? state1 state2)) |
| 235 | + (equivalent-states? dfa1 state1 state2)) |
| 236 | + (rename-states! dfa1 state2 state1)) |
| 237 | + (loop1 (cdr states2)))) |
| 238 | + (loop0 (cdr states1)))))) |
| 239 | + |
| 240 | + |
| 241 | + |
| 242 | +;; Returns true if q1 and q2 are equivalent states. |
| 243 | +;; Two states in a dfa are equivalent if |
| 244 | +;; for every symbol in the alphabet they go the |
| 245 | +;; next state. They must also both be either final or not |
| 246 | +;; final. |
240 | 247 | (define (equivalent-states? dfa1 q1 q2) |
241 | 248 | (if (not (equal? (member q1 (dfa-final-states dfa1)) |
242 | | - (member q2 (dfa-final-states dfa2)))) |
| 249 | + (member q2 (dfa-final-states dfa1)))) |
243 | 250 | #f |
244 | 251 | (let loop ((symbols (dfa-alphabet dfa1))) |
245 | 252 | (cond ((null? symbols) |
|
250 | 257 | (else |
251 | 258 | (loop (cdr symbols))))))) |
252 | 259 |
|
253 | | -(define (dfa-minimize! dfa1) |
254 | | - (let loop0 ((states1 (dfa-states dfa1))) |
255 | | - (if (not (null? states1)) |
256 | | - (let loop1 ((states2 (dfa-states dfa2))) |
257 | | - (if (not (null? states2)) |
258 | | - (let ((state1 (car states1)) |
259 | | - (state2 (car states2))) |
260 | | - (if (and (not (equal? state1 state2)) |
261 | | - (equivalent? state1 state2)) |
262 | | - (rename-states! dfa1 state2 state1)) |
263 | | - (loop1 (cdr states2)))) |
264 | | - (loop0 (cdr states2)))))) |
265 | | - |
266 | | - |
| 260 | +;; Takes a dfa and renames all occurrences of state1 to state2 |
267 | 261 | (define (rename-states! dfa1 state1 state2) |
268 | 262 | (define (replace-state x) |
269 | 263 | (if (equal? x state1) state2 x)) |
270 | | - (let ((new-trans (map |
271 | | - (lambda (trans) |
272 | | - (let ((q1 (replace-state (first trans))) |
273 | | - (q2 (replace-state (third trans)))) |
274 | | - (list q1 (second trans) q2))) |
275 | | - (dfa-tranisition-list dfa1))) |
276 | | - (new-start (replace-state (dfa-start-state dfa1))) |
277 | | - (new-final (map replace-state (dfa-final-states dfa1)))) |
278 | | - (dfa-transition-list-set! new-trans) |
279 | | - (dfa-start-state-set! new-start) |
280 | | - (dfa-final-states-set! new-final))) |
281 | | - |
282 | | - |
283 | | -(define (dfa-less dfa1 dfa2) |
284 | | - (dfa-intersection dfa1 (dfa-complement dfa2))) |
285 | | -;; (let* ((i (dfa-complement dfa2)) |
286 | | -;; (l (dfa-intersection dfa1 i))) |
287 | | -;; (print "inv")(read) |
288 | | -;; (show-graph (graph i)) |
289 | | -;; (print "dfa1")(read) |
290 | | -;; (show-graph (graph dfa1)) |
291 | | -;; (print "intersection")(read) |
292 | | -;; (show-graph (graph l)) |
293 | | -;; l)) |
294 | | - |
| 264 | + (let ((new-start (replace-state (dfa-start-state dfa1))) |
| 265 | + (new-final (map replace-state (dfa-final-states dfa1)))) |
| 266 | + (dfa-start-state-set! dfa1 new-start) |
| 267 | + (dfa-final-states-set! dfa1 new-final) |
| 268 | + ;; Replace all references to state1 in the list of transitions |
| 269 | + (let loop ((transitions (dfa-transition-list dfa1)) |
| 270 | + (new-trans (list))) |
| 271 | + (if (not (null? transitions)) |
| 272 | + (let* ((trans (car transitions)) |
| 273 | + (q1 (replace-state (first trans))) |
| 274 | + (q2 (replace-state (third trans))) |
| 275 | + (n-trans (list q1 (second trans) q2))) |
| 276 | + ;; avoid duplicate transitions |
| 277 | + (if (equal? (first trans) state1) |
| 278 | + (loop (cdr transitions) new-trans) |
| 279 | + (loop (cdr transitions) (cons n-trans new-trans)))) |
| 280 | + (dfa-transition-list-set! dfa1 new-trans))))) |
| 281 | + |
295 | 282 |
|
296 | 283 | (define (dfa-remove-unreachable-states! dfaA) |
297 | 284 | (let loop ((unreachable-states (%unreachable-states dfaA))) |
|
422 | 409 | '(qA) |
423 | 410 | '(d))) |
424 | 411 |
|
| 412 | +(define test-dfa-m |
| 413 | + (dfa |
| 414 | + 'q0 |
| 415 | + '((q0 a q1) |
| 416 | + (q0 b q2) |
| 417 | + (q1 a q3) |
| 418 | + (q1 b q4) |
| 419 | + (q2 a q4) |
| 420 | + (q2 b q3) |
| 421 | + (q3 a q5) |
| 422 | + (q3 b q5) |
| 423 | + (q4 a q5) |
| 424 | + (q4 b q5) |
| 425 | + (q5 a q5) |
| 426 | + (q5 b q5)) |
| 427 | + '(q5) |
| 428 | + '(a b))) |
| 429 | + |
425 | 430 | (define (main argv) |
426 | | - (view |
| 431 | + (view (graph test-dfa-m)) |
| 432 | + (dfa-minimize! test-dfa-m) |
| 433 | + (view (graph test-dfa-m)) |
| 434 | + |
| 435 | + (exit) |
427 | 436 |
|
428 | 437 | ; (print-dfa test-dfa) |
429 | 438 | ; (print-dfa test-dfa1) |
|
0 commit comments