main
Matthew Butterick 10 years ago
parent 7f02c1f13b
commit e165daf7fb

@ -0,0 +1,83 @@
#lang typed/racket
(require "ocm-typed.rkt")
(require typed/rackunit)
(require math)
(define m0 (matrix ((25.0 42.0 57.0 78.0 90.0 103.0 123.0 142.0 151.0)
(21.0 35.0 48.0 65.0 76.0 85.0 105.0 123.0 130.0)
(13.0 26.0 35.0 51.0 58.0 67.0 86.0 100.0 104.0)
(10.0 20.0 28.0 42.0 48.0 56.0 75.0 86.0 88.0)
(20.0 29.0 33.0 44.0 49.0 55.0 73.0 82.0 80.0)
(13.0 21.0 24.0 35.0 39.0 44.0 59.0 65.0 59.0)
(19.0 25.0 28.0 38.0 42.0 44.0 57.0 61.0 52.0)
(35.0 37.0 40.0 48.0 48.0 49.0 62.0 62.0 49.0)
(37.0 36.0 37.0 42.0 39.0 39.0 51.0 50.0 37.0)
(41.0 39.0 37.0 42.0 35.0 33.0 44.0 43.0 29.0)
(58.0 56.0 54.0 55.0 47.0 41.0 50.0 47.0 29.0)
(66.0 64.0 61.0 61.0 51.0 44.0 52.0 45.0 24.0)
(82.0 76.0 72.0 70.0 56.0 49.0 55.0 46.0 23.0)
(99.0 91.0 83.0 80.0 63.0 56.0 59.0 46.0 20.0)
(124.0 116.0 107.0 100.0 80.0 71.0 72.0 58.0 28.0)
(133.0 125.0 113.0 106.0 86.0 75.0 74.0 59.0 25.0)
(156.0 146.0 131.0 120.0 97.0 84.0 80.0 65.0 31.0)
(178.0 164.0 146.0 135.0 110.0 96.0 92.0 73.0 39.0))))
(define m (matrix->list* m0))
(define m2 (matrix->list* (matrix-transpose m0)))
(check-true (smawky? m))
(check-true (smawky? m2))
(: simple-entry->value Entry->Value-Type)
(define (simple-entry->value e)
(fl (cast e Real)))
;; proc must return a value even for out-of-bounds i and j
(: simple-proc Matrix-Proc-Type)
(define (simple-proc i j) (cast (fl (with-handlers [(exn:fail? (λ(exn) (* -1 i)))]
((inst list-ref Value-Type) ((inst list-ref (Listof Value-Type)) m i) j))) Value-Type))
(: simple-proc2 Matrix-Proc-Type)
(define (simple-proc2 i j) (cast (fl (with-handlers [(exn:fail? (λ(exn) (* -1 i)))]
((inst list-ref Value-Type) ((inst list-ref (Listof Value-Type)) m2 i) j))) Value-Type))
(check-equal? (simple-proc 0 2) 57.0) ; 0th row, 2nd col
(check-equal? (simple-proc2 2 0) 57.0) ; flipped
(define row-indices (cast (list->vector (range (length m))) (Vectorof Nonnegative-Integer)))
(define col-indices (cast (list->vector (range (length (car m)))) (Vectorof Nonnegative-Integer)))
(define result (concave-minima row-indices col-indices simple-proc simple-entry->value))
(check-equal?
(for/list : (Listof (List (U Index-Type Value-Type) (U Index-Type Value-Type))) ([j (in-vector col-indices)])
(define h (cast (hash-ref result j) (HashTable Symbol (U Index-Type Value-Type))))
(list (hash-ref h 'value) (hash-ref h 'row-idx)))
'((10.0 3) (20.0 3) (24.0 5) (35.0 5) (35.0 9) (33.0 9) (44.0 9) (43.0 9) (20.0 13))) ; checked against SMAWK.py
#|
(define o (make-ocm simple-proc simple-entry->value))
(check-equal?
(for/list : (Listof (Pairof Integer Any)) ([j (in-vector col-indices)])
(define h (hash-ref result j))
(list (hash-ref h 'value) (hash-ref h 'row-idx)))
'((10 3) (20 3) (24 5) (35 5) (35 9) (33 9) (44 9) (43 9) (20 13))) ; checked against SMAWK.py
(check-equal?
(for/list : (Listof (Pairof Integer Any)) ([j (in-vector col-indices)])
(list (min-value o j) (min-index o j)))
'((0 none) (42 0) (48 1) (51 2) (48 3) (55 4) (59 5) (61 6) (49 7))) ; checked against SMAWK.py
(define o2 (make-ocm simple-proc2))
(define row-indices2 (list->vector (range (length m2))))
(define col-indices2 (list->vector (range (length (car m2)))))
(define result2 (concave-minima row-indices2 col-indices2 simple-proc2 identity))
(check-equal?
(for/list : (Listof (Pairof Integer Any)) ([j (in-vector col-indices2)])
(define h (hash-ref result2 j))
(list (hash-ref h 'value) (hash-ref h 'row-idx)))
'((25 0) (21 0) (13 0) (10 0) (20 0) (13 0) (19 0) (35 0) (36 1) (29 8) (29 8) (24 8) (23 8) (20 8) (28 8) (25 8) (31 8) (39 8))) ; checked against SMAWK.py
(check-equal?
(for/list : (Listof (Pairof Integer Any)) ([j (in-vector col-indices2)])
(list (min-value o2 j) (min-index o2 j)))
'((0 none) (21 0) (13 0) (10 0) (20 0) (13 0) (19 0) (35 0) (36 1) (29 8) (-9 9) (-10 10) (-11 11) (-12 12) (-13 13) (-14 14) (-15 15) (-16 16))) ; checked against SMAWK.py
|#

@ -1,26 +1,9 @@
#lang typed/racket/base
(require (for-syntax racket/base racket/syntax))
(require/typed sugar/cache [make-caching-proc (Procedure . -> . Procedure)])
(require racket/list sugar/debug rackunit racket/function racket/vector "logger-typed.rkt")
(require racket/list sugar/debug racket/function racket/vector "logger-typed.rkt")
(define-logger ocm)
#|
Totally monotone matrix searching algorithms.
The offline algorithm in ConcaveMinima is from Agarwal, Klawe, Moran,
Shor, and Wilbur, Geometric applications of a matrix searching algorithm,
Algorithmica 2, pp. 195-208 (1987).
The online algorithm in OnlineConcaveMinima is from Galil and Park,
A linear time algorithm for concave one-dimensional dynamic programming,
manuscript, 1989, which simplifies earlier work on the same problem
by Wilbur (J. Algorithms 1988) and Eppstein (J. Algorithms 1990).
D. Eppstein, March 2002, significantly revised August 2005
|#
;(provide smawky? make-ocm reduce reduce2 (prefix-out ocm- (combine-out min-value min-index)))
(provide smawky? Entry->Value-Type Value-Type Index-Type Matrix-Proc-Type make-ocm reduce reduce2 concave-minima (prefix-out ocm- (combine-out min-value min-index)))
(: select-elements ((Listof Any) (Listof Index-Type) . -> . (Listof Any)))
(define (select-elements xs is)
@ -180,31 +163,11 @@ D. Eppstein, March 2002, significantly revised August 2005
minima)
#|
Search for the minimum value in each column of a matrix.
The return value is a dictionary mapping ColIndices to pairs
(value,rowindex). We break ties in favor of earlier rows.
The matrix is defined implicitly as a function, passed
as the third argument to this routine, where Matrix(i,j)
gives the matrix value at row index i and column index j.
The matrix must be concave, that is, satisfy the property
Matrix(i,j) > Matrix(i',j) => Matrix(i,j') > Matrix(i',j')
for every i<i' and j<j'; that is, in every submatrix of
the input matrix, the positions of the column minima
must be monotonically nondecreasing.
The rows and columns of the matrix are labeled by the indices
given in order by the first two arguments. In most applications,
these arguments can simply be integer ranges.
|#
;; The return value `minima` is a hash:
;; the keys are col-indices (integers)
;; the values are pairs of (value row-index).
(: concave-minima (((Vectorof Index-Type)) ((Vectorof Index-Type) Matrix-Proc-Type Entry->Value-Type) . ->* . HashTableTop))
(define (concave-minima row-indices [col-indices (vector)] [matrix-proc (cast (make-caching-proc identity) Matrix-Proc-Type)] [entry->value (cast identity Entry->Value-Type)])
(: concave-minima ((Vectorof Index-Type) (Vectorof Index-Type) Matrix-Proc-Type Entry->Value-Type . -> . HashTableTop))
(define (concave-minima row-indices col-indices matrix-proc entry->value)
;((vector?) ((or/c #f vector?) procedure? procedure?) . ->* . hash?)
(define reduce-proc reduce2)
(define interpolate-proc interpolate2)
@ -215,52 +178,6 @@ D. Eppstein, March 2002, significantly revised August 2005
(interpolate-proc (cast odd-column-minima (HashTable Any Any)) row-indices col-indices matrix-proc entry->value))))
#|
Online concave minimization algorithm of Galil and Park.
OnlineConcaveMinima(Matrix,initial) creates a sequence of pairs
(self.value(j),self.index(j)), where
self.value(0) = initial,
self.value(j) = min { Matrix(i,j) | i < j } for j > 0,
and where self.index(j) is the value of j that provides the minimum.
Matrix(i,j) must be concave, in the same sense as for ConcaveMinima.
We never call Matrix(i,j) until value(i) has already been computed,
so that the Matrix function may examine previously computed values.
Calling value(i) for an i that has not yet been computed forces
the sequence to be continued until the desired index is reached.
Calling iter(self) produces a sequence of (value,index) pairs.
Matrix(i,j) should always return a value, rather than raising an
exception, even for j larger than the range we expect to compute.
If j is out of range, a suitable value to return that will not
violate concavity is Matrix(i,j) = -i. It will not work correctly
to return a flag value such as None for large j, because the ties
formed by the equalities among such flags may violate concavity.
|#
;; Online Concave Minima object
;(struct $ocm (values indices finished matrix-proc base tentative) #:transparent #:mutable)
;; State used by self.value(), self.index(), and iter(self) =
;; $ocm-values, $ocm-indices, $ocm-finished
#|
State used by the internal algorithm:
$ocm-matrix, $ocm-base, $ocm-tentative
We allow self._values to be nonempty for indices > finished,
keeping invariant that
(1) self._values[i] = Matrix(self._indices[i], i),
(2) if the eventual correct value of self.index(i) < base,
then self._values[i] is nonempty and correct.
In addition, we keep a column index self._tentative, such that
(3) if i <= tentative, and the eventual correct value of
self.index(i) <= finished, then self._values[i] is correct.
|#
(define no-value 'none)
(define-syntax-rule (@ hashtable key)
@ -269,20 +186,15 @@ In addition, we keep a column index self._tentative, such that
(define-syntax-rule (! hashtable key value)
(hash-set! hashtable key value))
(: ocm-ref (OCM-Type Index-Type . -> . Any))
(define (ocm-ref ocm key)
(vector-ref ocm key))
(: ocm-set! (OCM-Type Index-Type Any . -> . Void))
(define (ocm-set! ocm key value)
(vector-set! ocm key value))
(define-type OCM-Type (Vector Any Any Any Any Any Any Any))
(define-type Index-Type Nonnegative-Integer)
(define-type Matrix-Proc-Type (Index-Type Index-Type . -> . Any))
(define-type Entry->Value-Type (Any . -> . Flonum))
(define-type Value-Type Flonum)
(define-type Initial-Value-Type Value-Type)
(define-type No-Value-Type Symbol)
(define-type Finished-Value-Type Index-Type)
(define-type Matrix-Proc-Type (Index-Type Index-Type . -> . Value-Type))
(define-type Entry->Value-Type (Any . -> . Value-Type))
;(define-type OCM-Type (Vector (Vectorof Value-Type) (Vectorof (U Index-Type No-Value-Type)) Finished-Value-Type Matrix-Proc-Type Entry->Value-Type Index-Type Index-Type))
(define-type OCM-Type (Vector Any Any Any Any Any Any))
(define o:min-values 0)
(define o:min-row-indices 1)
(define o:finished 2)
@ -291,57 +203,121 @@ In addition, we keep a column index self._tentative, such that
(define o:base 5)
(define o:tentative 6)
(: make-ocm ((Procedure) (Any Procedure) . ->* . OCM-Type))
(define (make-ocm matrix-proc [initial-value 0][entry->value identity])
(: ocm-matrix-proc (OCM-Type . -> . Matrix-Proc-Type))
(define (ocm-matrix-proc o)
(cast (vector-ref o o:matrix-proc) Matrix-Proc-Type))
(: ocm-set-matrix-proc (OCM-Type Matrix-Proc-Type . -> . Void))
(define (ocm-set-matrix-proc o proc)
(vector-set! o o:matrix-proc (cast proc Matrix-Proc-Type)))
(: ocm-entry->value (OCM-Type . -> . Entry->Value-Type))
(define (ocm-entry->value o)
(cast (vector-ref o o:entry->value) Entry->Value-Type))
(: ocm-set-entry->value (OCM-Type Entry->Value-Type . -> . Void))
(define (ocm-set-entry->value o proc)
(vector-set! o o:entry->value (cast proc Entry->Value-Type)))
(: ocm-finished (OCM-Type . -> . Finished-Value-Type))
(define (ocm-finished o)
(cast (vector-ref o o:finished) Finished-Value-Type))
(: ocm-set-finished (OCM-Type Finished-Value-Type . -> . Void))
(define (ocm-set-finished o v)
(vector-set! o o:finished (cast v Finished-Value-Type)))
(: ocm-tentative (OCM-Type . -> . Index-Type))
(define (ocm-tentative o)
(cast (vector-ref o o:tentative) Index-Type))
(: ocm-set-tentative (OCM-Type Index-Type . -> . Void))
(define (ocm-set-tentative o v)
(vector-set! o o:tentative (cast v Index-Type)))
(: ocm-base (OCM-Type . -> . Index-Type))
(define (ocm-base o)
(cast (vector-ref o o:tentative) Index-Type))
(: ocm-set-base (OCM-Type Index-Type . -> . Void))
(define (ocm-set-base o v)
(vector-set! o o:tentative (cast v Index-Type)))
(: ocm-min-values (OCM-Type . -> . (Vectorof Value-Type)))
(define (ocm-min-values o)
(cast (vector-ref o o:min-values) (Vectorof Value-Type)))
(: ocm-set-min-values (OCM-Type (Vectorof Value-Type) . -> . Void))
(define (ocm-set-min-values o vs)
(vector-set! o o:min-values (cast vs (Vectorof Value-Type))))
(: ocm-min-row-indices (OCM-Type . -> . (Vectorof (U Index-Type No-Value-Type))))
(define (ocm-min-row-indices o)
(cast (vector-ref o o:min-row-indices) (Vectorof (U Index-Type No-Value-Type))))
(: ocm-set-min-row-indices (OCM-Type (Vectorof (U Index-Type No-Value-Type)) . -> . Void))
(define (ocm-set-min-row-indices o vs)
(vector-set! o o:min-row-indices (cast vs (Vectorof (U Index-Type No-Value-Type)))))
(: make-ocm ((Matrix-Proc-Type Entry->Value-Type) (Initial-Value-Type) . ->* . OCM-Type))
(define (make-ocm matrix-proc entry->value [initial-value 0.0])
(log-ocm-debug "making new ocm")
(define ocm (cast (make-vector 7) OCM-Type))
(ocm-set! ocm o:min-values (vector initial-value))
(ocm-set! ocm o:min-row-indices (vector no-value))
(ocm-set! ocm o:finished 0)
(ocm-set! ocm o:matrix-proc (make-caching-proc matrix-proc))
(ocm-set! ocm o:entry->value entry->value) ; for converting matrix values to an integer
(ocm-set! ocm o:base 0)
(ocm-set! ocm o:tentative 0)
(cast ocm OCM-Type))
(ocm-set-min-values ocm (vector initial-value))
(ocm-set-min-row-indices ocm (vector no-value))
(ocm-set-finished ocm 0)
(ocm-set-matrix-proc ocm matrix-proc)
(ocm-set-entry->value ocm entry->value) ; for converting matrix values to an integer
(ocm-set-base ocm 0)
(ocm-set-tentative ocm 0)
ocm)
;; Return min { Matrix(i,j) | i < j }.
(: min-value (OCM-Type Index-Type . -> . Any))
(define (min-value ocm j)
(if (< (cast (ocm-ref ocm o:finished) Real) j)
(if (< (cast (ocm-finished ocm) Real) j)
(begin (advance! ocm) (min-value ocm j))
(vector-ref (cast (ocm-ref ocm o:min-values) VectorTop) j)))
(vector-ref (ocm-min-values ocm) j)))
;; Return argmin { Matrix(i,j) | i < j }.
(: min-index (OCM-Type Index-Type . -> . Index-Type))
(: min-index (OCM-Type Index-Type . -> . (U Index-Type No-Value-Type)))
(define (min-index ocm j)
(if (< (cast (ocm-ref ocm o:finished) Real) j)
(if (< (cast (ocm-finished ocm) Real) j)
(begin (advance! ocm) (min-index ocm j))
((inst vector-ref Index-Type) (cast (ocm-ref ocm o:min-row-indices) (Vectorof Index-Type)) j)))
((inst vector-ref (U Index-Type No-Value-Type)) (ocm-min-row-indices ocm) j)))
;; Finish another value,index pair.
(: advance! (OCM-Type . -> . Void))
(define (advance! ocm)
(define next (add1 (cast (ocm-ref ocm o:finished) Index-Type)))
(log-ocm-debug "advance! ocm to next = ~a" (add1 (cast (ocm-ref ocm o:finished) Number)))
(define next (add1 (ocm-finished ocm)))
(log-ocm-debug "advance! ocm to next = ~a" (add1 (ocm-finished ocm)))
(cond
;; First case: we have already advanced past the previous tentative
;; value. We make a new tentative value by applying ConcaveMinima
;; to the largest square submatrix that fits under the base.
[(> next (cast (ocm-ref ocm o:tentative) Real))
(log-ocm-debug "advance: first case because next (~a) > tentative (~a)" next (ocm-ref ocm o:tentative))
(define rows : (Vectorof Index-Type) (list->vector (range (cast (ocm-ref ocm o:base) Index-Type) next)))
(ocm-set! ocm o:tentative (+ (cast (ocm-ref ocm o:finished) Number) (vector-length rows)))
(define cols : (Vectorof Index-Type) (list->vector (range next (add1 (cast (ocm-ref ocm o:tentative) Index-Type)))))
(define minima (concave-minima rows cols (cast (ocm-ref ocm o:matrix-proc) Matrix-Proc-Type) (cast (ocm-ref ocm o:entry->value) Entry->Value-Type)))
[(> next (ocm-tentative ocm))
(log-ocm-debug "advance: first case because next (~a) > tentative (~a)" next (ocm-tentative ocm))
(define rows : (Vectorof Index-Type) (list->vector (range (ocm-base ocm) next)))
(ocm-set-tentative ocm (+ (ocm-finished ocm) (vector-length rows)))
(define cols : (Vectorof Index-Type) (list->vector (range next (add1 (ocm-tentative ocm)))))
(define minima (concave-minima rows cols (ocm-matrix-proc ocm) (ocm-entry->value ocm)))
(error 'stop)
(for ([col (in-vector cols)])
(cond
[(>= col (vector-length (cast (ocm-ref ocm o:min-values) VectorTop)))
(ocm-set! ocm o:min-values (vector-append-item (cast (ocm-ref ocm o:min-values) (Vectorof Any)) (@ (cast (@ minima col) HashTableTop) 'value)))
(ocm-set! ocm o:min-row-indices (vector-append-item (cast (ocm-ref ocm o:min-row-indices) (Vectorof Any)) (@ (cast (@ minima col) HashTableTop) 'row-idx)))]
[(< ((cast (ocm-ref ocm o:entry->value) Entry->Value-Type) (@ (cast (@ minima col) HashTableTop) 'value)) ((cast (ocm-ref ocm o:entry->value) Entry->Value-Type) (vector-ref (cast (ocm-ref ocm o:min-values) VectorTop) col)))
(ocm-set! ocm o:min-values ((inst vector-set Index-Type) (cast (ocm-ref ocm o:min-values) (Vectorof Index-Type)) col (cast (@ (cast (@ minima col) HashTableTop) 'value) Index-Type)))
(ocm-set! ocm o:min-row-indices ((inst vector-set Index-Type) (cast (ocm-ref ocm o:min-row-indices) (Vectorof Index-Type)) col (cast (@ (cast (@ minima col) HashTableTop) 'row-idx) Index-Type)))]))
(ocm-set! ocm o:finished next)]
[(>= col (vector-length (ocm-min-values ocm)))
(ocm-set-min-values ocm (vector-append-item (ocm-min-values ocm) (@ (cast (@ minima col) HashTableTop) 'value)))
(ocm-set-min-row-indices ocm (vector-append-item (ocm-min-row-indices ocm) (@ (cast (@ minima col) HashTableTop) 'row-idx)))]
[(< ((ocm-entry->value ocm) (@ (cast (@ minima col) HashTableTop) 'value)) ((ocm-entry->value ocm) (vector-ref (ocm-min-values ocm) col)))
(ocm-set-min-values ocm ((inst vector-set Index-Type) (ocm-min-values ocm) col (cast (@ (cast (@ minima col) HashTableTop) 'value) Index-Type)))
(ocm-set-min-row-indices ocm ((inst vector-set Index-Type) (ocm-min-row-indices ocm) col (cast (@ (cast (@ minima col) HashTableTop) 'row-idx) Index-Type)))]))
(ocm-set-finished ocm next)]
[else
;; Second case: the new column minimum is on the diagonal.
@ -349,23 +325,23 @@ In addition, we keep a column index self._tentative, such that
;; so we can clear out all our work from higher rows.
;; As in the fourth case, the loss of tentative is
;; amortized against the increase in base.
(define diag ((cast (ocm-ref ocm o:matrix-proc) Matrix-Proc-Type) (sub1 next) next))
(define diag ((ocm-matrix-proc ocm) (sub1 next) next))
(cond
[(< ((cast (ocm-ref ocm o:entry->value) Entry->Value-Type) diag) ((cast (ocm-ref ocm o:entry->value) Entry->Value-Type) (vector-ref (cast (ocm-ref ocm o:min-values) (Vectorof Any)) next)))
[(< ((ocm-entry->value ocm) diag) ((ocm-entry->value ocm) (vector-ref (ocm-min-values ocm) next)))
(log-ocm-debug "advance: second case because column minimum is on the diagonal")
(ocm-set! ocm o:min-values (vector-set (cast (ocm-ref ocm o:min-values) (Vectorof Any)) next diag))
(ocm-set! ocm o:min-row-indices (vector-set (cast (ocm-ref ocm o:min-row-indices) (Vectorof Any)) next (sub1 next)))
(ocm-set! ocm o:base (sub1 next))
(ocm-set! ocm o:tentative next)
(ocm-set! ocm o:finished next)]
(ocm-set-min-values ocm (vector-set (ocm-min-values ocm) next diag))
(ocm-set-min-row-indices ocm (vector-set (ocm-min-row-indices ocm) next (sub1 next)))
(ocm-set-base ocm (sub1 next))
(ocm-set-tentative ocm next)
(ocm-set-finished ocm next)]
;; Third case: row i-1 does not supply a column minimum in
;; any column up to tentative. We simply advance finished
;; while maintaining the invariant.
[(>= ((cast (ocm-ref ocm o:entry->value) Entry->Value-Type) ((cast (ocm-ref ocm o:matrix-proc) Matrix-Proc-Type) (sub1 next) (cast (ocm-ref ocm o:tentative) Index-Type)))
((cast (ocm-ref ocm o:entry->value) Entry->Value-Type) (vector-ref (cast (ocm-ref ocm o:min-values) (Vectorof Any)) (cast (ocm-ref ocm o:tentative) Index-Type))))
[(>= ((ocm-entry->value ocm) ((ocm-matrix-proc ocm) (sub1 next) (ocm-tentative ocm)))
((ocm-entry->value ocm) (vector-ref (ocm-min-values ocm) (ocm-tentative ocm))))
(log-ocm-debug "advance: third case because row i-1 does not suppply a column minimum")
(ocm-set! ocm o:finished next)]
(ocm-set-finished ocm next)]
;; Fourth and final case: a new column minimum at self._tentative.
;; This allows us to make progress by incorporating rows
@ -375,14 +351,15 @@ In addition, we keep a column index self._tentative, such that
;; this step) can be amortized against the increase in base.
[else
(log-ocm-debug "advance: fourth case because new column minimum")
(ocm-set! ocm o:base (sub1 next))
(ocm-set! ocm o:tentative next)
(ocm-set! ocm o:finished next)])]))
(ocm-set-base ocm (sub1 next))
(ocm-set-tentative ocm next)
(ocm-set-finished ocm next)])]))
(: print (OCM-Type . -> . Void))
(define (print ocm)
(displayln (ocm-ref ocm o:min-values))
(displayln (ocm-ref ocm o:min-row-indices)))
(displayln (ocm-min-values ocm))
(displayln (ocm-min-row-indices ocm)))
(: smawky? ((Listof (Listof Real)) . -> . Boolean))
(define (smawky? m)
@ -412,67 +389,3 @@ In addition, we keep a column index self._tentative, such that
#t)) Boolean))))
(and increasing-minima? monotone?))
(module+ test
(require rackunit)
(define m '((25 42 57 78 90 103 123 142 151)
(21 35 48 65 76 85 105 123 130)
(13 26 35 51 58 67 86 100 104)
(10 20 28 42 48 56 75 86 88)
(20 29 33 44 49 55 73 82 80)
(13 21 24 35 39 44 59 65 59)
(19 25 28 38 42 44 57 61 52)
(35 37 40 48 48 49 62 62 49)
(37 36 37 42 39 39 51 50 37)
(41 39 37 42 35 33 44 43 29)
(58 56 54 55 47 41 50 47 29)
(66 64 61 61 51 44 52 45 24)
(82 76 72 70 56 49 55 46 23)
(99 91 83 80 63 56 59 46 20)
(124 116 107 100 80 71 72 58 28)
(133 125 113 106 86 75 74 59 25)
(156 146 131 120 97 84 80 65 31)
(178 164 146 135 110 96 92 73 39)))
(define m2 (apply map list m))
(check-true (smawky? m))
(check-true (smawky? m2))
;; proc must return a value even for out-of-bounds i and j
(define (simple-proc i j) (with-handlers [(exn:fail? (λ(exn) (* -1 i)))]
(list-ref (list-ref m i) j)))
(define (simple-proc2 i j) (with-handlers [(exn:fail? (λ(exn) (* -1 i)))]
(list-ref (list-ref m2 i) j)))
(check-equal? (simple-proc 0 2) 57) ; 0th row, 2nd col
(check-equal? (simple-proc2 2 0) 57) ; flipped
(define o (make-ocm simple-proc))
(define row-indices (list->vector (range (length m))))
(define col-indices (list->vector (range (length (car m)))))
(define result (concave-minima row-indices col-indices simple-proc identity))
(check-equal?
(for/list : (Listof (Pairof Integer Any)) ([j (in-vector col-indices)])
(define h (hash-ref result j))
(list (hash-ref h 'value) (hash-ref h 'row-idx)))
'((10 3) (20 3) (24 5) (35 5) (35 9) (33 9) (44 9) (43 9) (20 13))) ; checked against SMAWK.py
(check-equal?
(for/list : (Listof (Pairof Integer Any)) ([j (in-vector col-indices)])
(list (min-value o j) (min-index o j)))
'((0 none) (42 0) (48 1) (51 2) (48 3) (55 4) (59 5) (61 6) (49 7))) ; checked against SMAWK.py
(define o2 (make-ocm simple-proc2))
(define row-indices2 (list->vector (range (length m2))))
(define col-indices2 (list->vector (range (length (car m2)))))
(define result2 (concave-minima row-indices2 col-indices2 simple-proc2 identity))
(check-equal?
(for/list : (Listof (Pairof Integer Any)) ([j (in-vector col-indices2)])
(define h (hash-ref result2 j))
(list (hash-ref h 'value) (hash-ref h 'row-idx)))
'((25 0) (21 0) (13 0) (10 0) (20 0) (13 0) (19 0) (35 0) (36 1) (29 8) (29 8) (24 8) (23 8) (20 8) (28 8) (25 8) (31 8) (39 8))) ; checked against SMAWK.py
(check-equal?
(for/list : (Listof (Pairof Integer Any)) ([j (in-vector col-indices2)])
(list (min-value o2 j) (min-index o2 j)))
'((0 none) (21 0) (13 0) (10 0) (20 0) (13 0) (19 0) (35 0) (36 1) (29 8) (-9 9) (-10 10) (-11 11) (-12 12) (-13 13) (-14 14) (-15 15) (-16 16))) ; checked against SMAWK.py
)

Loading…
Cancel
Save