
 SEQUENTIAL vs. RANDOM ACCESS


       SEQUENTIAL ACCESS
(define long-list (list 1 2 3 ... 1000))

(list-ref long-list 900)
 COST:	900 cdr's

(subst 111 900 long-list)
 COST:  900 cdr's
	900 cons

reading nth element O(n) time
writing nth element O(n) time and space


     RANDOM ACCESS

(define long-vec (vector 1 2 3 ... 1000))

(vector-ref long-vec 900)
  COST:  1 unit of time

(vector-set! long-vec 900 111)
  COST:  1 unit of time

reading nth element: O(1) time
writing nth element: O(1) time


   A PICTURE OF A VECTOR VALUE

     < a,   b,   c,   d,   e >    values

       0    1    2    3    4      indexes

    #( a    b    c    d    e )    printed


v: (-> ({0,1,2,3,4}) symbol)
v(0) = a
v(1) =      b
v(2) =           c
v(3) =                d
v(4) =                     e

Def: a (vector T) value is a mapping
 from {0,1,...,n-1} to objects of type T,
where n >= 0


Def: a (vector T) object is
     (make-vector n x)
  or (vector e0 e1 ... en)
where n has type natural
  and x, e0, e1, ..., en have type T


      BASIC PROCEDURES FOR VECTORS

vector : (-> (T ...) (vector T))

make-vector :
  (and (-> (natural T) (vector T))
       (-> (natural) (vector datum)))

vector?: (-> (datum) boolean)

vector-length : (-> ((vector T)) natural)

vector-ref: (-> ((vector T) natural) T)
 ; REQUIRES: the natural number is
 ; less than the length of the vector.

vector-set! : (-> ((vector T) natural T)
                  void)
 ; REQUIRES: the natural number is
 ; less than the length of the vector


(view (vector 1 2 3)) =prints=> #(1 2 3)
(view (vector 3)) =prints=> #(3)
; assume length > 0


(list->vector '()) ==> #()
(list->vector '(a b)) ==> #(a b)
(list->vector (list 0 1 2 3))
     ==> #(0 1 2 3)

list->vector : (-> ((list T)) (vector T))


; compare Program 9.23

(define list->vector
  ; TYPE: (-> ((list T)) (vector T))
  (lambda (ls)
    (let ((vec (make-vector (length ls))))
      (letrec
        ((convert!
            ; TYPE: (-> ((list T) natural)
            ;           void)
           (lambda (ls* i)
	     ; REQUIRES: i <= (length ls),
             ; ls* = (list-tail ls i),
	     ; for all 0 <= j < i:
             ;  (vector-ref vec j)
             ;  = (list-ref ls j)
	     ; MODIFIES: vec
	     ; EFFECT: put ls* into vec
             ; starting at index i
             (if (not (null? ls*))
                 (begin
                   (vector-set! vec i
                     (car ls*))
                   (convert! (cdr ls*)
                            (add1 i)))))))
        (convert! ls 0))
      vec)))


(vector-copy '#(3 4 5)) ==> #(5 8 9)
(eq? v (vector-copy v)) ==> #f
(equal? v (vector-copy v)) ==> #t

vector-copy : (-> ((vector T)) (vector T))

Don't mutate the arguments.
Return a new vector.


Def: an object is mutated if it's value
is changed (e.g., by vector-set!).

Def: an object is new iff
it didn't exist before the call
(so it's not eq? to anything else)


(define vector-copy
  (lambda (v)
    ; ENSURES: result is a new vector
    ; that has the same value as v
    (let ((len (vector-length v)))
      (let ((vec (make-vector len)))
	(letrec
	 ((init!
	   ; TYPE: (-> (natural) void)
	   (lambda (i)
	     ; REQUIRES: i < len
             ; for all 0 <= j < i:
             ;  (vector-ref v j)
             ;  = (vector-ref vec j)
             ; MODIFIES: vec
             ; EFFECT: put the elements
	     ; of v into vec, start at i
	     (if (< i len)
		 (begin
		   (vector-set!
		     vec
		     i
		     (vector-ref v i))
		   (init! (add1 i)))))))
	  (init! 0))
	vec))))


     YOU WRITE

(vec+ '#(3 4 5) '(2 3 4))
   ==> #(5 8 9)

vec+ : (-> ((vector number)
            (vector number))
           (vector number))

Assume the arguments have the same length.
Don't mutate the arguments.
Return a new vector.


   VECTOR-GENERATOR

1. make a new vector
2. fill in as directed
3. return the new vector


((vector-generator (lambda (i) i)) 4)
  ==> #(0 1 2 3)

; want to be able to define...

(define vector-copy
  (lambda (v)
    ((vector-generator
       (lambda (i) (vector-ref v i)))
     (vector-length v))))

(define vec+
  (lambda (v1 v2)
    ((vector-generator
       (lambda (i)
         (+ (vector-ref v1 i)
            (vector-ref v2 i))))
     (vector-length v1))))

vector-generator: 
 (-> ((-> (natural) T))
     (-> (natural) (vector T)))


; - Program 9.21, pg. 283 -

(define vector-generator
  (lambda (gen-proc)
    (lambda (size)
      (let ((vec (make-vector size)))
        (letrec
          ((loop!
            ; TYPE: (-> (natural) void)
	    (lambda (i)
	      ; REQUIRES: i <= size
	      ; and for all 0 <= j < i,
	      ; (vector-ref vec j)
              ;  = (gen-proc j)
	      ; MODIFIES: vec
	      ; EFFECT: initialize indexes
	      ;  i up to size-1
	      (if (< i size)
		  (begin
		    (vector-set!
		      vec
		      i
		      (gen-proc i))
		    (loop! (add1 i)))))))
          (loop! 0))
        vec))))


   YOU WRITE

(list->vector '()) ==> #()
(list->vector '(a b)) ==> #(a b)
(list->vector (list 0 1 2 3))
     ==> #(0 1 2 3)

list->vector : (-> ((list T)) (vector T))

   USING vector-generator (and list-ref)


(vector-map add1 '#(1 2 3))
   ==> #(2 3 4)

; - Program 9.9, pg. 273 -
(define vector-map
  ; TYPE: (-> ((-> (S) T) ((vector S)))
  ;           (vector T))
  (lambda (proc vec)
    ; ENSURES: result is a new vector that
    ; has ith element proc applied to
    ; the ith element of vec
    ((vector-generator
         (lambda (i)
	   (proc (vector-ref vec i))))
     (vector-length vec))))


; - Program 9.11, pg. 274 -

(define vector-apply-elementwise-to-both 
  ; TYPE: (-> ((-> (S T) U))
  ;           (-> ((vector S) (vector T))
  ;               (vector U)))
  (lambda (proc) 
    ; REQUIRES: the lengths of vec1
    ;             and vec2 are equal
    ; ENSURES: result is a new vector that
    ; has ith element proc applied to
    ; the ith element of vec1 and vec2
    (lambda (vec1 vec2) 
      (let ((gen-proc 
              (lambda (i) 
                (proc
		 (vector-ref vec1 i)
		 (vector-ref vec2 i)))))
        ((vector-generator gen-proc)
	 (vector-length vec1))))))

Exercise: use this to define vec+ and vec*
(vec+ (vector 3 4) (vector 5 6)))
        ==> #(8 10)


(vector-sum (vector )) ==> 0
(vector-sum (vector 3 4 5)) ==> 12

vector-sum: (-> ((vector number)) number)


; - Program 9.13, pg. 275 -

(define vector-sum
  (lambda (vec) 
    ; ENSURES: result is the sum of
    ;          the numbers in vec
    (let ((size (vector-length vec)))
      (letrec 
        ((helper
           (lambda (i) 
             (if (= i size) 
                 0 
                 (+ (vector-ref vec i)
		    (helper (add1 i)))))))
        (helper 0)))))

Exercise: write vector-product.
(vector-product (vector )) ==> 1
(vector-product (vector 3 4 5)) ==> 60


; - Program 9.15, pg. 277 -

(define vector-accumulate 
  ;TYPE: (-> ((-> (S T) T) T)
  ;          (-> ((vector S)) (vector T)))
  (lambda (proc seed)
    (lambda (vec)
      (let ((size (vector-length vec)))
        (letrec 
          ((helper
	     ; TYPE: (-> (nat) (vector T))
             (lambda (i)
               (if (= i size)
                   seed 
                   (proc 
		    (vector-ref vec i)
		    (helper (add1 i)))))))
          (helper 0))))))

Exercise: Use this to define vector->list
(vector->list (vector 'next 'please))
   ==> (next please)


 MUTATING VEC-MULT-BY-SCALAR!

> (define v (vector 1 2 3 4))
> (vec-mult-by-scalar! v 3)
> v
#(3 6 9 12)

vec-mult-by-scalar! :
  (-> ((vector number) number) void)


  FUNCTIONAL VEC-MULT-BY-SCALAR

(vec-mult-by-scalar (vector 1 2 3 4) 3)
  ==> #(3 6 9 12)

Return a new vector, do not mutate the arg


(define vec-mult-by-scalar
  ; TYPE: (-> ((vector number) number)
  ;           (vector number))           
  (lambda (v n)
    ; ENSURES: result is a new vector
    ;     with ith element mutiplied by n
    (let ((v-copy (vector-copy v)))
      (vec-mult-by-scalar! v-copy n)
       v-copy)))


 MUTATING VECTOR-REVERSE!

> (define v (vector 1 2 3 4))
> (vector-reverse! v)
> v
#(4 3 2 1)

vector-reverse! : (-> ((vector T)) void)


(define vector-reverse! ;; cf. Prog 9.26
  ;TYPE: (-> ((vector T)) void)
  (lambda (vec)
    ; MODIFIES: vec
    ; EFFECT: reverse vec in place
    (let ((swapv! (swap!-maker vec)))
      (letrec 
        ((switch! ;: (-> (nat nat ) void)
	  (lambda (i j)
	    ; REQUIRES: 0 <= i <= j
	    ; j <= (vector-length vec),
	    ; positions 0..i and j..length
	    ;  have already been swapped
	    (if (< i j)
		(begin
		  (swapv! i j)
		  (switch! (add1 i)
			   (sub1 j)))))))
        (switch! 0
	        (sub1 (vector-length vec))
		)))))
(define swap!-maker ;; Prog 9.27
  ; TYPE: (-> ((vector T))
  ;           (-> (natural natural)
  ;               (vector T)))
  (lambda (vec)
    (lambda (index1 index2)
     (let ((temp (vector-ref vec index1)))
        (vector-update!
          (vector-update! vec index1
		  (vector-ref vec index2))
          index2
          temp)))))


(define vector-reverse
  ; TYPE:(-> ((vector T)) (vector T))
  (lambda (vec)
    (let ((vec-copy (vector-copy vec)))
       (vector-reverse! vec-copy)
       vec-copy)))

; Compare Program 9.24 in the text


; - Program 9.22, pg. 283 -

(define vector-update!
  ; TYPE: (-> ((vector T) natural T)
  ;           (vector T))
  (lambda (vec i c) 
    ; REQUIRES: i is a legal index for vec
    ; MODIFIES: vec
    ; EFFECT: make the ith element of vec
    ;         be c, and return vec
    (vector-set! vec i c) 
    vec))


	A MATRIX	

"Jones, J."  "2117 Plum St."    "412-8421"
"Jones, M."  "1392 First Ave."  "424-7773"
"Jose, M."   "3314 Valley Dr."  "421-0035"
"Joslin, J." "2550 Western"     "412-5531"


    MATRIX VALUES

Def: a (matrix T) value is a mapping
from {(0,0),(0,1),...,(0,n-1),
      (1,0),(1,1),...,(1,n-1),
      ...
      (m-1,0),(m-1,1),...,(m-1,n-1)}
to objects of type T,
where m >= 0 is the number of rows
  and n >= 0 is the number of columns


     MATRIX OBJECTS

Def: a (matrix T) object is
 ((matrix-generator f) m n)
where f has type (-> (natural natural) T),
      m >= 0 is the number of rows
  and n >= 0 is the number of columns.


	BASIC PROCEDURES FOR MATRICES

matrix-generator:
  (-> ((-> (natural natural) T))
      (-> (natural natural)
          (matrix T)))


num-rows: (-> ((matrix T)) natural)
num-cols: (-> ((matrix T)) natural)


matrix-ref: (-> ((matrix T))
                (-> (natural natural) T))
; REQUIRES: the first natural is less than
; the number of columns of the matrix, and
; the second is less than number of rows.


matrix-set! : (-> ((matrix T))
                  (-> (natural natural T)
                      void))
; REQUIRES: the first natural is less than
; the number of columns of the matrix, and
; the second is less than number of rows.


 REPRESENTING MATRICES

Example matrix:
   0   1   2   3
  10  11  12  13
  20  21  22  23


	   ROW MAJOR ORDER

0  1  2  3  10  11  12  13  20  21  22  23


	COLUMN MAJOR ORDER
	
0  10  20  1  11  21  2  12  22  3  13  23


   OUR REPRESENTATION (IDEA IS ROW MAJOR)

(vector
0  1  2  3  10  11  12  13  20  21  22  23
   4)


    INDEX OF i,j IN REP
	
 (row-size)*i+j

; - Program 9.32, pg. 294 -

(define matrix-ref
  (lambda (mat)
    (let ((ncols (num-cols mat)))
      (lambda (i j)
        (vector-ref mat
		    (+ (* i ncols) j))))))


; - Program 9.30, pg. 293 -

(define num-cols
  (lambda (mat)
    (let ((size
	   (sub1 (vector-length mat))))
      (vector-ref mat size))))


; - Program 9.31, pg. 294 -

(define num-rows
  (lambda (mat)
    (let ((size (sub1 (vector-length mat))))
      (/ size (vector-ref mat size)))))


; - Program 9.33, pg. 295 -

(define matrix-generator
  ; TYPE: (-> ((-> (natural natural) T))
  ;           (-> (natural natural)
  ;               (matrix  T)))
  (lambda (gen-proc)
    (lambda (nrows ncols)
      ; ENSURES: result is a matrix of
      ; nrows by ncols whose (i,j)th
      ; element is (gen-proc i j)
      (let ((size (* nrows ncols)))
        (let ((vec-gen-proc
		; TYPE: (-> (natural) void)
                (lambda (k)
		  ; REQUIRES: k <= size
		  ; ENSURES: result is
		  ; the kth element of the
		  ; row vector rep,
		  ; or ncols if k = size
                  (if (< k size)
                      (gen-proc
		       (quotient k ncols) 
		       (remainder k ncols)
		       )
                      ncols))))
          ((vector-generator vec-gen-proc)
           (add1 size)))))))


Exercise: use this to write make-matrix
like make-vector, but curried.
	((make-matrix 0.0) 7 3)


> (define mat ((matrix-generator
		 (lambda (i j)
		   (+ (* 10 i) j)))
	       3 4))
> ((row-of mat) 2)
#(20 21 22 23)

Return a new vector.

(define row-of 
  ; TYPE: (-> ((matrix T))
  ;           (-> (natural) (vector T)))
  (lambda (mat)
    ; ENSURES: (result i) is the ith
    ; row vector of mat,
    ; if 0 <= i < (num-rows mat)
    (let ((mat-ref (matrix-ref mat))
          (number-of-columns
	   (num-cols mat)))
      (lambda (i)
	; REQUIRES: i < (num-rows mat)
        (let ((gen-proc
	       (lambda (j) (mat-ref i j)))
	      )
          ((vector-generator gen-proc)
	   number-of-columns))))))


; - Program 9.39, pg. 300 -

(define matrix-set!
  ; TYPE: (-> ((matrix T))
  ;          (-> (natural natural T) void)
  (lambda (mat)
    (let ((ncols (num-cols mat)))
      (lambda (i j obj)
	; REQUIRES: i < ncols,
	; and j < (num-rows mat)
	; MODIFIES: mat
	; EFFECT: make the (i,j)th
	; element in mat be obj
        (vector-set!
	 mat
	 (+ (* i ncols) j) obj)))))


		SILLY TOY COMPANY

       stl pls rbr               Ames DSM

widget  4   2   2        steel     $8  $7
xylophn 5   2   2        plastic   $4  $5
yack    4   3   1        rubber    $5  $4
zebra   5   5   2


	       Ames     DSM

widgets        $50      $46
xylophn        $58      $53
yack           $49      $47
zebra          $54      $54


(define dot-prod-internal
  ; TYPE: (-> ((matrix number) (matrix number))
  ;           (-> (natural number) number))
  (lambda (mat-a mat-b)
    ; REQUIRES: (num-cols mat-a) = (num-rows mat-b)
    ; ENSURES: (result i j) is the dot product of
    ; the ith row of mat-a and the jth col of mat-b
    (let ((ncols-a (num-cols mat-a))
          (a-ref (matrix-ref mat-a))
          (b-ref (matrix-ref mat-b)))
      (lambda (i j)
	(letrec
	  ((dot-prod ; TYPE: (-> (natural number) number)
	     (lambda (r acc)
	       ; REQUIRES: 0 <= r <= ncols-a
	       ; and acc is the sum of all products of
	       ; the form a[i,r']*b[r',j] for all 0 <= r' < r.
	       ; ENSURES: result is dot product of
	       ; the ith row of mat-a and the jth col of mat-b
	       (if (= r ncols-a)
		   acc
		   (dot-prod (add1 r) 
		     (+ acc (* (a-ref i r) 
			       (b-ref r j))))))))
	  (dot-prod 0 0))))))

(define matrix-product
  ; TYPE: (-> ((matrix number) (matrix number))
  ;           (matrix number))
  (lambda (mat-a mat-b)
    ; REQUIRES: (num-cols mat-a) = (num-rows mat-b)
    ; ENSURES: result is the product of mat-a and mat-b,
    ; i.e., a (num-rows mat-a) by (num-cols mat-b) matrix
    ; whose (i,j)th element is teh dot-product of the ith row of a
    ; and the jth column of b
    (let ((ncols-a (num-cols mat-a))
	  (dot-prod (dot-prod-internal mat-a mat-b)))
      (if (not (= ncols-a (num-rows mat-b)))
          (error "matrix-product:"
		 "The matrices are not compatible.")
	  ((matrix-generator dot-prod) 
	   (num-rows mat-a) (num-cols mat-b))))))

; imperative version, compare program 9.38
(define matrix-product-imp
  ; TYPE: (-> ((matrix number) (matrix number))
  ;           (matrix number))
  (lambda (mat-a mat-b)
    ; REQUIRES: (num-cols mat-a) = (num-rows mat-b)
    ; ENSURES: result is the product of mat-a and mat-b,
    ; i.e., a (num-rows mat-a) by (num-cols mat-b) matrix
    ; whose (i,j)th element is teh dot-product of the ith row of a
    ; and the jth column of b
    (let ((nrows-a (num-rows mat-a))  ; NOTE: different than above!!!
	  (ncols-b (num-cols mat-b))) ; ditto
      (if (not (= (num-cols mat-a) (num-rows mat-b)))
          (error "matrix-product:"
		 "The matrices are not compatible.")
          (let ((mat ((make-matrix 0.0) (num-rows mat-a) (num-cols mat-b)))
		(dot-prod (dot-product-internal mat-a mat-b)))
	    (let ((mat-set! (matrix-set! mat)))
	      (letrec
		((each-row! ; TYPE: (-> (natural) void)
		   (lambda (i)
		     ; REQUIRES: i <= nrows-a
		     ; MODIFIES: mat
		     ; EFFECT: set each element in the ith row of mat to
		     ; the dot-product of the ith row of mat-a and the
		     ; appropriate column of mat-b
		     (letrec
		       ((each-col! ; TYPE: (-> (natural) void)
			  (lambda (j)
			    ; REQUIRES: j <= ncols-b
			    ; EFFECT: set the (i,j)th element of mat to
			    ; the dot-product of the ith row of mat-a and the
			    ; jth column of mat-b
			    (if (< j ncols-b)
				(begin
				  (mat-set! i j (dot-prod i j))
				  (each-col! (add1 j)))))))
		       (if (< i nrows-a)
			    (begin
			      (each-col! 0)
			      (each-row! (add1 i))))))))
		(each-row! 0)
		mat)))))))

