;;; ;;; ---- Vector searching ;;; Time-stamp: <05/03/07 18:19:59 Zhu Chongkai> ;;; ;;; Copyright (C) 2005 by Zhu Chongkai. ;;; ;;; This file is part of SRFI-43. ;;; SRFI-43 is free software; you can redistribute it and/or ;;; modify it under the terms of the GNU Lesser General Public ;;; License as published by the Free Software Foundation; either ;;; version 2.1 of the License, or (at your option) any later version. ;;; SRFI-43 is distributed in the hope that it will be useful, ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;; Lesser General Public License for more details. ;;; You should have received a copy of the GNU Lesser General Public ;;; License along with SRFI-43; if not, write to the Free Software ;;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ;;; Author: Zhu Chongkai ;; ;; ;; Commentary: ;; Based on the reference implementation by Taylor Campbell and hence: ;;; Copyright (C) 2003, 2004 Taylor Campbell. ;;; All rights reserved. ;;; ;;; You may do as you please with this code, as long as you refrain ;;; from removing this copyright notice or holding me liable in _any_ ;;; circumstances for _any_ damages that may be caused by it; and you ;;; may quote sections from it as you please, as long as you credit me. (module searching mzscheme (require "util.ss") (provide vector-index vector-index-right vector-skip vector-skip-right vector-binary-search vector-any vector-every) ;; All the functions (except vector-binary-search) here can be ;; abstracted, but for performance I didn't do so. ;;; (VECTOR-INDEX ...) ;;; -> exact, nonnegative integer or #F ;;; (PREDICATE? ...) -> boolean ; N vectors -> N args ;;; Search left-to-right across VECTOR ... in parallel, returning the ;;; index of the first set of values VALUE ... such that (PREDICATE? ;;; VALUE ...) returns a true value; if no such set of elements is ;;; reached, return #F. (define vector-index (letrec ((loop1 (lambda (pred? vec len i) (cond ((= i len) #f) ((pred? (vector-ref vec i)) i) (else (loop1 pred? vec len (add1 i)))))) (loop2+ (lambda (pred? vectors len i) (cond ((= i len) #f) ((apply pred? (vectors-ref vectors i)) i) (else (loop2+ pred? vectors len (add1 i))))))) (lambda (pred? vec . vectors) (unless (procedure? pred?) (apply raise-type-error 'vector-index "procedure" 0 pred? vec vectors)) (unless (vector? vec) (apply raise-type-error 'vector-index "vector" 1 pred? vec vectors)) (if (null? vectors) (loop1 pred? vec (vector-length vec) 0) (begin (check-list-of-vecs vectors 'vector-index 2 (list* pred? vec vectors)) (loop2+ pred? (cons vec vectors) (%smallest-length vectors (vector-length vec)) 0)))))) ;;; (VECTOR-SKIP ...) ;;; -> exact, nonnegative integer or #F ;;; (PREDICATE? ...) -> boolean ; N vectors -> N args ;;; (vector-index (lambda elts (not (apply PREDICATE? elts))) ;;; VECTOR ...) ;;; Like VECTOR-INDEX, but find the index of the first set of values ;;; that do _not_ satisfy PREDICATE?. (define vector-skip (letrec ((loop1 (lambda (pred? vec len i) (cond ((= i len) #f) ((pred? (vector-ref vec i)) (loop1 pred? vec len (add1 i))) (else i)))) (loop2+ (lambda (pred? vectors len i) (cond ((= i len) #f) ((apply pred? (vectors-ref vectors i)) (loop2+ pred? vectors len (add1 i))) (else i))))) (lambda (pred? vec . vectors) (unless (procedure? pred?) (apply raise-type-error 'vector-skip "procedure" 0 pred? vec vectors)) (unless (vector? vec) (apply raise-type-error 'vector-skip "vector" 1 pred? vec vectors)) (if (null? vectors) (loop1 pred? vec (vector-length vec) 0) (begin (check-list-of-vecs vectors 'vector-skip 2 (list* pred? vec vectors)) (loop2+ pred? (cons vec vectors) (%smallest-length vectors (vector-length vec)) 0)))))) ;;; (VECTOR-INDEX-RIGHT ...) ;;; -> exact, nonnegative integer or #F ;;; (PREDICATE? ...) -> boolean ; N vectors -> N args ;;; Right-to-left variant of VECTOR-INDEX. (define vector-index-right (letrec ((loop1 (lambda (pred? vec i) (if (zero? i) #f (let ((i (sub1 i))) (if (pred? (vector-ref vec i)) i (loop1 pred? vec i)))))) (loop2+ (lambda (pred? vectors i) (if (zero? i) #f (let ((i (sub1 i))) (if (apply pred? (vectors-ref vectors i)) i (loop2+ pred? vectors i))))))) (lambda (pred? vec . vectors) (unless (procedure? pred?) (apply raise-type-error 'vector-index-right "procedure" 0 pred? vec vectors)) (unless (vector? vec) (apply raise-type-error 'vector-index-right "vector" 1 pred? vec vectors)) (if (null? vectors) (loop1 pred? vec (vector-length vec)) (begin (check-list-of-vecs vectors 'vector-index-right 2 (list* pred? vec vectors)) (loop2+ pred? (cons vec vectors) (%smallest-length vectors (vector-length vec)))))))) ;;; (VECTOR-SKIP-RIGHT ...) ;;; -> exact, nonnegative integer or #F ;;; (PREDICATE? ...) -> boolean ; N vectors -> N args ;;; Right-to-left variant of VECTOR-SKIP. (define vector-skip-right (letrec ((loop1 (lambda (pred? vec i) (if (zero? i) #f (let ((i (sub1 i))) (if (pred? (vector-ref vec i)) (loop1 pred? vec i) i))))) (loop2+ (lambda (pred? vectors i) (if (zero? i) #f (let ((i (sub1 i))) (if (apply pred? (vectors-ref vectors i)) (loop2+ pred? vectors i) i)))))) (lambda (pred? vec . vectors) (unless (procedure? pred?) (apply raise-type-error 'vector-skip-right "procedure" 0 pred? vec vectors)) (unless (vector? vec) (apply raise-type-error 'vector-skip-right "vector" 1 pred? vec vectors)) (if (null? vectors) (loop1 pred? vec (vector-length vec)) (begin (check-list-of-vecs vectors 'vector-skip-right 2 (list* pred? vec vectors)) (loop2+ pred? (cons vec vectors) (%smallest-length vectors (vector-length vec)))))))) ;;; (VECTOR-BINARY-SEARCH ) ;;; -> exact, nonnegative integer or #F ;;; (CMP ) -> integer ;;; positive -> VALUE1 > VALUE2 ;;; zero -> VALUE1 = VALUE2 ;;; negative -> VALUE1 < VALUE2 ;;; Perform a binary search through VECTOR for VALUE, comparing each ;;; element to VALUE with CMP. (define (vector-binary-search vec value cmp) (unless (vector? vec) (raise-type-error 'vector-binary-search "vector" 0 vec value cmp)) (unless (procedure-arity-includes? cmp 2) (raise-type-error 'vector-binary-search "procedure of arity 2" 2 vec value cmp)) (let loop ((start 0) (end (vector-length vec)) (j -1)) (let ((i (quotient (+ start end) 2))) (if (= i j) #f (let ((comparison (cmp (vector-ref vec i) value))) (unless (integer? comparison) (raise-type-error 'vector-binary-search "procedure that returns an integer" 2 vec value cmp)) (cond ((zero? comparison) i) ((positive? comparison) (loop start i i)) (else (loop i end i)))))))) ;;; (VECTOR-ANY ...) -> value ;;; Apply PRED? to each parallel element in each VECTOR ...; if PRED? ;;; should ever return a true value, immediately stop and return that ;;; value; otherwise, when the shortest vector runs out, return #F. ;;; The iteration and order of application of PRED? across elements ;;; is of the vectors is strictly left-to-right. (define vector-any (letrec ((loop1 (lambda (pred? vec i len) (and (not (= i len)) (or (pred? (vector-ref vec i)) (loop1 pred? vec (add1 i) len))))) (loop2+ (lambda (pred? vectors i len) (and (not (= i len)) (or (apply pred? (vectors-ref vectors i)) (loop2+ pred? vectors (add1 i) len)))))) (lambda (pred? vec . vectors) (unless (procedure? pred?) (apply raise-type-error 'vector-any "procedure" 0 pred? vec vectors)) (unless (vector? vec) (apply raise-type-error 'vector-any "vector" 1 pred? vec vectors)) (if (null? vectors) (loop1 pred? vec 0 (vector-length vec)) (begin (check-list-of-vecs vectors 'vector-any 2 (list* pred? vec vectors)) (loop2+ pred? (cons vec vectors) 0 (%smallest-length vectors (vector-length vec)))))))) ;;; (VECTOR-EVERY ...) -> value ;;; Apply PRED? to each parallel value in each VECTOR ...; if PRED? ;;; should ever return #F, immediately stop and return #F; otherwise, ;;; if PRED? should return a true value for each element, stopping at ;;; the end of the shortest vector, return the last value that PRED? ;;; returned. In the case that there is an empty vector, return #T. ;;; The iteration and order of application of PRED? across elements ;;; is of the vectors is strictly left-to-right. (define vector-every (letrec ((loop1 (lambda (pred? vec i len) (or (> i len) (if (= i len) (pred? (vector-ref vec i)) (and (pred? (vector-ref vec i)) (loop1 pred? vec (add1 i) len)))))) (loop2+ (lambda (pred? vectors i len) (or (> i len) (if (= i len) (apply pred? (vectors-ref vectors i)) (and (apply pred? (vectors-ref vectors i)) (loop2+ pred? vectors (add1 i) len))))))) (lambda (pred? vec . vectors) (unless (procedure? pred?) (apply raise-type-error 'vector-every "procedure" 0 pred? vec vectors)) (unless (vector? vec) (apply raise-type-error 'vector-every "vector" 1 pred? vec vectors)) (if (null? vectors) (loop1 pred? vec 0 (sub1 (vector-length vec))) (begin (check-list-of-vecs vectors 'vector-every 2 (list* pred? vec vectors)) (loop2+ pred? (cons vec vectors) 0 (sub1 (%smallest-length vectors (vector-length vec))))))))))