(module chase-sequence
( make-sequence
next-permutation)
(cond-expand
(chicken-4
(import scheme chicken)
(use
(only lolevel object-copy)
(only srfi-4 make-u32vector u32vector-ref u32vector-set!)
(only iset make-bit-vector bit-vector-ref bit-vector-set!)) )
(chicken-5
(import scheme
(chicken base)
(chicken type)
(only (chicken memory representation) object-copy)
(only (srfi 4) make-u32vector u32vector-ref u32vector-set!)
(only iset make-bit-vector bit-vector-ref bit-vector-set!)) )
(else
(error "unknown CHICKEN; not chicken-4 or chicken-5") ) )
(: u32vector-swap! (u32vector fixnum fixnum -> void))
(define (u32vector-swap! u32v i j)
(let ((tmp (u32vector-ref u32v i)))
(u32vector-set! u32v i (u32vector-ref u32v j))
(u32vector-set! u32v j tmp) ) )
(define-type bit-vector u8vector)
(define-type chase-result (or boolean procedure fixnum vector bit-vector))
(define-type chase-sequence (#!optional symbol -> chase-result))
(define-type swap-listener (fixnum -> void))
(define-type chase-permutation (list-of vector))
(: next-permutation (chase-sequence -> (or boolean chase-permutation)))
(define (next-permutation cs)
(let (
(siz (cs 'num))
(cs-permutation (cs)) )
(and
cs-permutation
(let ((v (make-vector siz)))
(do ((i 0 (add1 i)))
((= i siz) v)
(vector-set! v i (cs-permutation i)))) ) ) )
(: make-sequence (vector #!optional fixnum swap-listener --> chase-sequence))
(define (make-sequence data-vector #!optional cut-point (swap-listener void))
(let* (
(num (vector-length data-vector))
(t (if (and cut-point (<= 1 cut-point num))
cut-point
num))
(s (- num t))
(r (if (positive? s) s t))
(data (object-copy data-vector))
(swaps 0)
(comb (make-u32vector num))
(ix (make-u32vector num))
(w (make-bit-vector (add1 num) #t))
(a (make-bit-vector num))
(swap-listener
(lambda (i)
(set! swaps (add1 swaps))
(swap-listener i))) )
(do ((i 0 (add1 i)))
((= i num))
(u32vector-set! comb i i)
(u32vector-set! ix i i)
(bit-vector-set! a i (>= i s)) )
(let ()
(define (adjacent-swap i)
# (u32vector-set! ix (u32vector-ref comb i) (add1 i))
(u32vector-set! ix (u32vector-ref comb (add1 i)) i)
(u32vector-swap! comb i (add1 i))
# # (swap-listener i) )
(define (move f t)
# # (if (< f t)
(do ((i f (add1 i)))
((= i t))
(adjacent-swap i) )
(do ((i (sub1 f) (sub1 i)))
((< i t))
(adjacent-swap i) ) ) )
(define (exchange l r)
# # # (move (u32vector-ref ix l) s) # (move (u32vector-ref ix r) (sub1 s)) (adjacent-swap (sub1 s)) # (bit-vector-set! a l #f)
# (bit-vector-set! a r #t) )
(define (move-right-one j)
# (exchange j (sub1 j))
(cond
((and (= r j) (> j 1))
(set! r (sub1 j)) )
((= r (sub1 j))
(set! r j) ) ) )
(define (move-right-two j)
# (if (bit-vector-ref a (- j 2))
(move-right-one j)
(begin
(exchange j (- j 2))
(cond
((= r j)
(set! r (if (> j 3) (- j 2) 1)))
((= r (- j 2))
(set! r (sub1 j)) ) ) ) ) )
(define (move-left-one j)
# (exchange (sub1 j) j)
(cond
((and (= r j) (> j 1))
(set! r (sub1 j)) )
((= r (sub1 j))
(set! r j) ) ) )
(define (move-left-two j)
# (if (bit-vector-ref a (sub1 j))
(move-left-one j)
(begin
# (exchange (- j 2) j)
(cond
((= r (- j 2))
(set! r j) )
((= r (sub1 j))
(set! r (- j 2)) ) ) ) ) )
(define (ref-proc i)
(vector-ref data (u32vector-ref comb i) ) )
(define (gen-partition)
(let ((j #f))
(do ((i r (add1 i)))
((bit-vector-ref w i) (set! j i))
(bit-vector-set! w i #t) )
(and
(not (= j num))
(let ((aj (bit-vector-ref a j)))
(bit-vector-set! w j #f)
(set! swaps 0)
(if (odd? j)
(if aj
(move-right-one j)
(move-left-two j) )
(if aj
(move-right-two j)
(move-left-one j) ) )
ref-proc ) ) ) )
(define (next-partition)
(set! next-partition gen-partition)
ref-proc )
(lambda (#!optional swapf)
(case swapf
((swaps) swaps )
((num) num )
((data) data )
((a) a )
(else (next-partition) ) ) ) ) ) )
)