176 lines
5.3 KiB
Scheme
176 lines
5.3 KiB
Scheme
;;; Functions to manipulate integer sets represented as lists of
|
|
;;; intervals.
|
|
;;;
|
|
;;; Sets are represented as lists of intervals, which are pairs (lower
|
|
;;; bound, upper bound), where both bounds are included. The lower
|
|
;;; bound must be an integer, the upper bound can either be an integer
|
|
;;; or the symbol 'max' to specify the maximum possible value of all
|
|
;;; intervals for the problem at hand. The specific value of this
|
|
;;; maximum is not known.
|
|
;;;
|
|
;;; The following implementation guarantees that sets are always in
|
|
;;; canonical form, that is their intervals are:
|
|
;;; - sorted in increasing order,
|
|
;;; - disjoint, and
|
|
;;; - non-contiguous (i.e. they do not touch each other).
|
|
;;;
|
|
;;; External dependencies: SRFI-1 (list library) and SRFI-23 (error).
|
|
|
|
(define (pairwise f l)
|
|
(or (< (length l) 2)
|
|
(and (f (first l) (second l)) (pairwise f (cdr l)))))
|
|
|
|
;;; Functions on bounds.
|
|
|
|
(define (b-max? bound) (eq? bound 'max))
|
|
|
|
(define (b< b1 b2)
|
|
(and (not (b-max? b1)) (or (b-max? b2) (< b1 b2))))
|
|
|
|
(define (b<= b1 b2)
|
|
(or (eq? b1 b2) (b< b1 b2)))
|
|
|
|
(define (bs<= . bounds)
|
|
(pairwise b<= bounds))
|
|
|
|
(define (b-pred bound)
|
|
(if (b-max? bound) (error "no predecessor to 'max'") (- bound 1)))
|
|
|
|
(define (b-succ bound)
|
|
(if (b-max? bound) (error "no successor to 'max'") (+ bound 1)))
|
|
|
|
;; Saturating successor.
|
|
(define (b-sat-succ bound)
|
|
(if (b-max? bound) bound (+ bound 1)))
|
|
|
|
(define (b-min b1 b2)
|
|
(cond ((b-max? b1) b2)
|
|
((b-max? b2) b1)
|
|
(else (min b1 b2))))
|
|
|
|
(define (b-max b1 b2)
|
|
(cond ((b-max? b1) b1)
|
|
((b-max? b2) b2)
|
|
(else (max b1 b2))))
|
|
|
|
;;; Functions on individual intervals (pairs of bounds).
|
|
|
|
(define i-make cons)
|
|
(define i-beg car)
|
|
(define i-end cdr)
|
|
|
|
;; Beware: the following syntax leads to multiple evaluations of each
|
|
;; interval expression!
|
|
(define-syntax let-int
|
|
(syntax-rules ()
|
|
((let-int ((beg-1 end-1 int-1) rest ...) body ...)
|
|
(let ((beg-1 (i-beg int-1)) (end-1 (i-end int-1)))
|
|
(let-int (rest ...) body ...)))
|
|
((let-int () body ...)
|
|
(begin body ...))))
|
|
|
|
(define (i-intersect? i1 i2)
|
|
(let-int ((b1 e1 i1) (b2 e2 i2))
|
|
(or (bs<= b1 b2 e1) (bs<= b2 b1 e2))))
|
|
|
|
(define (i-contiguous? i1 i2)
|
|
(let-int ((b1 e1 i1) (b2 e2 i2))
|
|
(or (bs<= b1 b2 (b-sat-succ e1)) (bs<= b2 b1 (b-sat-succ e2)))))
|
|
|
|
;; Defined only for contiguous intervals.
|
|
(define (i-union i1 i2)
|
|
(let-int ((b1 e1 i1) (b2 e2 i2))
|
|
(i-make (b-min b1 b2) (b-max e1 e2))))
|
|
|
|
(define (i-start-before? i1 i2)
|
|
(b< (i-beg i1) (i-beg i2)))
|
|
|
|
(define (i-end-before? i1 i2)
|
|
(b< (i-end i1) (i-end i2)))
|
|
|
|
;; Defined only for disjoint intervals.
|
|
(define i< i-start-before?)
|
|
|
|
(define (i-intersection i1 i2)
|
|
(if (i-intersect? i1 i2)
|
|
(list (let-int ((b1 e1 i1) (b2 e2 i2))
|
|
(i-make (b-max b1 b2) (b-min e1 e2))))
|
|
'()))
|
|
|
|
(define (i-difference i1 i2)
|
|
(if (i-intersect? i1 i2)
|
|
(let-int ((b1 e1 i1) (b2 e2 i2))
|
|
(let ((il (if (b< b1 b2) (list (i-make b1 (b-pred b2))) '()))
|
|
(ir (if (b< e2 e1) (list (i-make (b-succ e2) e1)) '())))
|
|
(append il ir)))
|
|
(list i1)))
|
|
|
|
;;; Functions on sets (lists of individual intervals).
|
|
|
|
(define (intset? thing)
|
|
;; TODO check that intervals are disjoint and increasing
|
|
(and (list? thing)
|
|
(every (lambda (pair)
|
|
(and (pair? pair)
|
|
(number? (car pair))
|
|
(or (number? (cdr pair)) (b-max? (cdr pair)))
|
|
(b< (car pair) (cdr pair))))
|
|
thing)))
|
|
|
|
(define (intset-union s1 s2)
|
|
(cond ((null? s1) s2)
|
|
((null? s2) s1)
|
|
(else
|
|
(let ((h1 (car s1)) (t1 (cdr s1))
|
|
(h2 (car s2)) (t2 (cdr s2)))
|
|
(cond ((i-contiguous? h1 h2)
|
|
(if (i-end-before? h1 h2)
|
|
(intset-union t1 (cons (i-union h1 h2) t2))
|
|
(intset-union (cons (i-union h1 h2) t1) t2)))
|
|
((i< h1 h2)
|
|
(cons h1 (intset-union t1 s2)))
|
|
(else ;(i< h2 h1)
|
|
(cons h2 (intset-union s1 t2))))))))
|
|
|
|
(define (intset-intersection s1 s2)
|
|
(if (or (null? s1) (null? s2))
|
|
'()
|
|
(let ((h1 (car s1)) (t1 (cdr s1))
|
|
(h2 (car s2)) (t2 (cdr s2)))
|
|
(if (i-end-before? h1 h2)
|
|
(append (i-intersection h1 h2) (intset-intersection t1 s2))
|
|
(append (i-intersection h1 h2) (intset-intersection s1 t2))))))
|
|
|
|
(define (intset-difference s1 s2)
|
|
(if (or (null? s1) (null? s2))
|
|
s1
|
|
(let ((h1 (car s1)) (t1 (cdr s1))
|
|
(h2 (car s2)) (t2 (cdr s2)))
|
|
(cond ((i-intersect? h1 h2)
|
|
(intset-difference (append (i-difference h1 h2) t1) s2))
|
|
((i< h1 h2)
|
|
(cons h1 (intset-difference t1 s2)))
|
|
(else
|
|
(intset-difference s1 t2))))))
|
|
|
|
(define (intset-range begin end)
|
|
`((,begin . ,end)))
|
|
|
|
(define (intset-singleton elem)
|
|
(intset-range elem elem))
|
|
|
|
(define (intset-adjoin elem set)
|
|
(intset-union set (intset-singleton elem)))
|
|
|
|
(define (intset-delete elem set)
|
|
(intset-difference set (intset-singleton elem)))
|
|
|
|
(define (intset-contains? elem set)
|
|
(any (lambda (i) (bs<= (i-beg i) elem (i-end i))) set))
|
|
|
|
(define (intset-map f set)
|
|
(if (null? set)
|
|
'()
|
|
(let ((fst (car set)))
|
|
(cons (f (car fst) (cdr fst)) (intset-map f (cdr set))))))
|