Add disjoint sum enum and fix enum

This commit is contained in:
Max New 2013-11-08 17:40:09 -06:00
parent 38b0906e48
commit 562cecd10c
3 changed files with 156 additions and 29 deletions

View File

@ -87,7 +87,7 @@
(define (loop pat) (define (loop pat)
(match-a-pattern (match-a-pattern
pat pat
[`any (sum/e any/e (many/e any/e))] [`any any/e]
[`number num/e] [`number num/e]
[`string string/e] [`string string/e]
[`natural natural/e] [`natural natural/e]
@ -175,6 +175,7 @@
(define term (define term
(fill-refs refpat)) (fill-refs refpat))
(λ (_) term)] (λ (_) term)]
[(name-ref n) [(name-ref n)
(λ (nv) (λ (nv)
(t-env-name-ref nv n))] (t-env-name-ref nv n))]
@ -218,10 +219,11 @@
(many/e char/e))) (many/e char/e)))
(define integer/e (define integer/e
(sum/e nats (disj-sum/e (cons nats (λ (n) (>= n 0)))
(map/e (λ (n) (- (+ n 1))) (cons (map/e (λ (n) (- (+ n 1)))
(λ (n) (- (- n) 1)) (λ (n) (- (- n) 1))
nats))) nats)
(λ (n) (< n 0)))))
;; This is really annoying so I turned it off ;; This is really annoying so I turned it off
(define real/e empty/e) (define real/e empty/e)
@ -238,11 +240,18 @@
(compose string->list symbol->string) (compose string->list symbol->string)
(many1/e char/e))) (many1/e char/e)))
(define base/e
(disj-sum/e (cons (const/e '()) null?)
(cons num/e number?)
(cons string/e string?)
(cons bool/e boolean?)
(cons var/e symbol?)))
(define any/e (define any/e
(sum/e num/e (fix/e +inf.f
string/e (λ (any/e)
bool/e (disj-sum/e (cons base/e (negate pair?))
var/e)) (cons (cons/e any/e any/e) pair?)))))
(define (unsupported pat) (define (unsupported pat)
(error 'generate-term "#:i-th does not support ~s patterns" pat)) (error 'generate-term "#:i-th does not support ~s patterns" pat))

View File

@ -3,6 +3,7 @@
racket/match racket/match
racket/list racket/list
racket/function racket/function
racket/promise
data/gvector) data/gvector)
(provide enum (provide enum
@ -14,6 +15,7 @@
const/e const/e
from-list/e from-list/e
sum/e sum/e
disj-sum/e
cons/e cons/e
dep/e dep/e
dep2/e ;; requires size (eventually should replace dep/e with this) dep2/e ;; requires size (eventually should replace dep/e with this)
@ -21,6 +23,7 @@
filter/e ;; very bad, only use for small enums filter/e ;; very bad, only use for small enums
except/e except/e
thunk/e thunk/e
fix/e
many/e many/e
many1/e many1/e
list/e list/e
@ -176,14 +179,17 @@
;; input list should not contain duplicates ;; input list should not contain duplicates
;; equality on eq? ;; equality on eq?
(define (from-list/e l) (define (from-list/e l)
(define rev-map
(for/hash ([i (in-naturals)]
[x (in-list l)])
(values x i)))
(if (empty? l) (if (empty? l)
empty/e empty/e
(enum (length l) (enum (length l)
(λ (n) (λ (n)
(list-ref l n)) (list-ref l n))
(λ (x) (λ (x)
(length (take-while l (λ (y) (hash-ref rev-map x)))))
(not (eq? x y)))))))))
;; take-while : Listof a, (a -> bool) -> Listof a ;; take-while : Listof a, (a -> bool) -> Listof a
(define (take-while l pred) (define (take-while l pred)
@ -278,6 +284,63 @@
(map-pairs/even (cdr l))))) (map-pairs/even (cdr l)))))
(apply sum/e (map-pairs sum/e identity (list* a b c rest)))])) (apply sum/e (map-pairs sum/e identity (list* a b c rest)))]))
(define (disj-sum/e e-p . e-ps)
(define/match (disj-sum2/e e-p1 e-p2)
[((cons e1 1?) (cons e2 2?))
;; Sum two enumerators of different sizes
(define (sum-uneven less/e less? more/e more?)
;; interleave until less/e is exhausted
;; pairsdone is 1+ the highest index using less/e
(define less-size (size less/e))
(define pairsdone (* 2 less-size))
(define (from-nat n)
(if (< n pairsdone)
(let-values ([(q r) (quotient/remainder n 2)])
;; Always put e1 first though!
(decode (match r
[0 e1]
[1 e2])
q))
(decode more/e (- n less-size))))
(define (to-nat x)
(cond [(less? x)
(* 2 (encode less/e x))]
[(more? x)
(define i (encode more/e x))
(if (< i less-size)
(+ (* 2 i) 1)
(+ (- i less-size) pairsdone))]
[else (error "bad term")]))
(enum (+ less-size (size more/e))
from-nat
to-nat))
(define s1 (size e1))
(define s2 (size e2))
(cond [(= 0 s1) e2]
[(= 0 s2) e1]
[(< s1 s2) (sum-uneven e1 1? e2 2?)]
[(< s2 s1) (sum-uneven e2 2? e1 1?)]
[else ;; both the same length, interleave them
(define (from-nats n)
(cond [(even? n) (decode e1 (/ n 2))]
[else (decode e2 (/ (- n 1) 2))]))
(define (to-nats x)
(cond [(1? x) (* (encode e1 x) 2)]
[(2? x) (+ 1 (* (encode e2 x) 2))]
[else (error "bad term")]))
(enum (+ s1 s2) from-nats to-nats)])])
(car
(foldr (λ (e-p1 e-p2)
(match* (e-p1 e-p2)
[((cons e1 1?) (cons e2 2?))
(cons (disj-sum2/e e-p1
(cons e2 (negate 1?)))
(λ (x)
(or (1? x)
(2? x))))]))
(cons empty/e (λ (_) #f))
(cons e-p e-ps))))
(define n*n (define n*n
(enum +inf.f (enum +inf.f
(λ (n) (λ (n)
@ -695,30 +758,33 @@
;; thunk/e : Nat or +-Inf, ( -> enum a) -> enum a ;; thunk/e : Nat or +-Inf, ( -> enum a) -> enum a
(define (thunk/e s thunk) (define (thunk/e s thunk)
(let* ([e #f] (define promise/e (delay (thunk)))
[get-e (λ ()
(or e
(and (set! e (thunk))
e)))])
(enum s (enum s
(λ (n) (λ (n)
(decode (get-e) n)) (decode (force promise/e) n))
(λ (x) (λ (x)
(encode (get-e) x))))) (encode (force promise/e) x))))
;; fix/e : size (enum a -> enum a) -> enum a
(define (fix/e size f/e)
(define self (delay (f/e (fix/e size f/e))))
(enum size
(λ (n)
(decode (force self) n))
(λ (x)
(encode (force self) x))))
;; many/e : enum a -> enum (listof a) ;; many/e : enum a -> enum (listof a)
;; or : enum a, #:length natural -> enum (listof a) ;; or : enum a, #:length natural -> enum (listof a)
(define many/e (define many/e
(case-lambda (case-lambda
[(e) [(e)
(thunk/e (fix/e (if (= 0 (size e))
(if (= 0 (size e))
0 0
+inf.f) +inf.f)
(λ () (λ (self)
(sum/e (disj-sum/e (cons (const/e '()) null?)
(const/e '()) (cons (cons/e e self) pair?))))]
(cons/e e (many/e e)))))]
[(e n) [(e n)
(list/e (build-list n (const e)))])) (list/e (build-list n (const e)))]))

View File

@ -125,6 +125,53 @@
(check-equal? (encode odd-or-even 3) 3) (check-equal? (encode odd-or-even 3) 3)
(check-bijection? odd-or-even))) (check-bijection? odd-or-even)))
(test-begin
(define bool-or-num
(disj-sum/e (cons bools/e boolean?)
(cons (from-list/e '(0 1 2 3)) number?)))
(define bool-or-nat
(disj-sum/e (cons bools/e boolean?)
(cons nats number?)))
(define nat-or-bool
(disj-sum/e (cons nats number?)
(cons bools/e boolean?)))
(define odd-or-even
(disj-sum/e (cons evens/e even?)
(cons odds/e odd?)))
(check-equal? (size bool-or-num) 6)
(check-equal? (decode bool-or-num 0) #t)
(check-equal? (decode bool-or-num 1) 0)
(check-equal? (decode bool-or-num 2) #f)
(check-equal? (decode bool-or-num 3) 1)
(check-equal? (decode bool-or-num 4) 2)
(check-equal? (decode bool-or-num 5) 3)
(check-exn exn:fail?
(λ ()
(decode bool-or-num 6)))
(check-bijection? bool-or-num)
(check-equal? (size bool-or-nat)
+inf.f)
(check-equal? (decode bool-or-nat 0) #t)
(check-equal? (decode bool-or-nat 1) 0)
(check-bijection? bool-or-nat)
(check-equal? (size odd-or-even)
+inf.f)
(check-equal? (decode odd-or-even 0) 0)
(check-equal? (decode odd-or-even 1) 1)
(check-equal? (decode odd-or-even 2) 2)
(check-exn exn:fail?
(λ ()
(decode odd-or-even -1)))
(check-equal? (encode odd-or-even 0) 0)
(check-equal? (encode odd-or-even 1) 1)
(check-equal? (encode odd-or-even 2) 2)
(check-equal? (encode odd-or-even 3) 3)
(check-bijection? odd-or-even))
;; cons/e tests ;; cons/e tests
(define bool*bool (cons/e bools/e bools/e)) (define bool*bool (cons/e bools/e bools/e))
(define 1*b (cons/e (const/e 1) bools/e)) (define 1*b (cons/e (const/e 1) bools/e))
@ -354,3 +401,8 @@
(except/e (up-to n) excepts)) (except/e (up-to n) excepts))
'(2 4 6))) '(2 4 6)))
(check-bijection? complicated) (check-bijection? complicated)
;; many/e tests
(define natss
(many/e nats))
(check-bijection? natss)