Solutions for exercise set #4

1. Vector operations.

;; The NORM procedure computes the square root of the sum of the squares
;; of the elements of a given vector.

(define norm
  (lambda (vec)

    ;; Make sure that VEC is a vector of numbers.

    (if (not ((vector-of number?) vec))
        (error 'norm "The argument must be a vector of numbers"))

    ;; Traverse the vector (from right to left, in this case), squaring
    ;; each element and adding the result to a running total.  After all
    ;; of the elements have been processed, extract and return the square
    ;; root of the running total.

    (let loop ((remaining (vector-length vec))
               (total 0))
      (if (zero? remaining)
          (sqrt total)
          (let ((next (- remaining 1)))
            (loop next (+ total (square (vector-ref vec next)))))))))

;; The VECTOR-OF procedure takes a predicate PRED as argument and returns a
;; procedure that takes any object as argument and determines whether it is
;; a vector in which PRED correctly characterizes every element.  (If it is
;; a vector that has no elements, the procedure returned by VECTOR-OF
;; returns #T, on the theory that PRED is ``vacuously true'' of the
;; vector's elements.) 

(define vector-of
  (lambda (pred)
    (lambda (obj)
      (and (vector? obj)
           (let loop ((remaining (vector-length obj)))
             (or (zero? remaining)
                 (let ((next (- remaining 1)))
                   (and (pred (vector-ref obj next))
                        (loop next)))))))))

;; The SQUARE procedure takes any number and returns the result of
;; multiplying it by itself.

(define square
  (lambda (n)

    ;; Make sure that N is a number.

    (if (not (number? n))
        (error 'square "The argument must be a number"))

    ;; Square it.

    (* n n)))

2. Vector construction.

;; Given a vector VEC of real numbers, the CUMULATIVE-TOTALS constructs and
;; returns another vector of the same length, with each position of the new
;; vector containing the sum of the elements of VEC up to and including the
;; corresponding position.

(define cumulative-totals
  (lambda (vec)

    ;; Make sure that VEC is a vector of real numbers.

    (if (not ((vector-of real?) vec))
        (error 'cumulative-totals
               "The argument must be a vector of real numbers"))

    ;; Allocate a RESULT vector to hold the cumulative totals.

    (let* ((len (vector-length vec))
           (result (make-vector len)))

      ;; Traverse both vectors from left to right, adding each element
      ;; of VEC to the running total and storing the new value of that
      ;; total in RESULT.

      (let loop ((position 0)
                 (total 0))
        (if (= position len)
            result
            (let ((new-total (+ total (vector-ref vec position))))
              (vector-set! result position new-total)
              (loop (+ position 1) new-total)))))))

3. Vector mutation.

;; The PARTITION procedure takes two arguments, the first, VEC, a vector of
;; strings and the second, PIVOT, a string, and rearranges the elements of
;; VEC so that every string that lexicographically precedes or equals PIVOT
;; is in a lower-numbered position than any of the strings that
;; lexicographically follows PIVOT.  It returns the number of elements of
;; VEC that lexicographicallly precede or equal PIVOT.

(define partition
  (lambda (vec pivot)

    ;; Make sure that VEC is a vector of strings.

    (if (not ((vector-of string?) vec))
        (error 'partition
               "The first argument must be a vector of strings")) 

    ;; Make sure that PIVOT is a string.

    (if (not (string? pivot))
        (error 'partition "The second argument must be a string"))

    ;; Traverse the vector from left to right, keeping a tally of the
    ;; elements that lexicographically precede or equal the pivot.  Each
    ;; time such an element is encountered, swap it into the position
    ;; indicated by the current value of the tally and then increment
    ;; the tally by one.  When all of the elements of the vector have
    ;; been examined, all of the elements that lexicographically precede
    ;; or equal the pivot will have been swapped into positions less
    ;; than the value of the tally, and all those in positions equal to
    ;; or greater than the tally will lexicographically follow the
    ;; pivot.  So the postcondition will have been met, and it remains
    ;; only to return the value of the tally.

    (let ((len (vector-length vec)))
      (let loop ((position 0)
                 (tally 0))
        (cond ((= position len) tally)
              ((string<=? (vector-ref vec position) pivot)
               (let ((temp (vector-ref vec position)))
                 (vector-set! vec position (vector-ref vec tally))
                 (vector-set! vec tally temp))
               (loop (+ position 1) (+ tally 1)))
              (else (loop (+ position 1) tally)))))))

This document is available on the World Wide Web as

http://www.math.grin.edu/courses/Scheme/solutions-4.html

created May 4, 1997
last revised May 28, 1997
John David Stone (stone@math.grin.edu)