#lang racket
(require loudhum)

;;; File:
;;;   binary-search-lab.rkt
;;; Authors:
;;;   Fahmida Hamid
;;;   Titus Klinge
;;;   Samuel A. Rebelsky
;;;   YOUR NAME HERE
;;; Summary:
;;;   Data and procedures for the lab on binary search.

; +---------------+------------------------------------------------------------
; | Provided Data |
; +---------------+

;;; Values:
;;;   simulated-students
;;;   simulated-students-by-id
;;;   simulated-students-by-year
;;; Type:
;;;   vector of lists
;;; Notes:
;;;   * Each list is of the form
;;;    (first-name:string last-name:string student-id:integer
;;;     major:string year:integer)
;;;   * In simualted-students, values are in alphabetical order by first name
;;;   * In simulated-students-by-id, values are in numeric order by id
;;;   * In simulated-students-by-year, values are in numeric order by year
(define simulated-students
  (vector
   (list "Amy"       "Zevon"    1336804 "Computer Science"  2019)
   (list "Bob"       "Smith"    1170605 "Mathematics"       2020)
   (list "Charlotte" "Davis"    1304091 "Independent"       2018)
   (list "Danielle"  "Jones"    1472662 "Undeclared"        2021)
   (list "Devon"     "Smith"    1546921 "Computer Science"  2018)
   (list "Erin"      "Anderson" 1320727 "Philosophy"        2019)
   (list "Fred"      "Stone"    1260057 "Linguistics"       2018)
   (list "Greg"      "Jones"    1668280 "Classics"          2020)
   (list "Heather"   "Jones"    1046860 "Classics"          2021)
   (list "Ira"       "Jackson"  1070103 "Political Science" 2022)
   (list "Janet"     "Smith"    1488985 "Chemistry"         2019)
   (list "Karla"     "Hill"     1821167 "Psychology"        2018)
   (list "Leo"       "Levens"   1399810 "English"           2019)
   (list "Maria"     "Moody"    1168059 "Computer Science"  2020)
   (list "Ned"       "Black"    1177023 "Russian"           2018)
   (list "Otto"      "White"    1908656 "Chinese"           2019)
   (list "Paula"     "Hall"     1218704 "Psychology"        2018)
   (list "Quentin"   "Smith"    1679081 "Art History"       2018)
   (list "Rebecca"   "Davis"    1658200 "Biology"           2020)
   (list "Sam"       "Sky"      1085519 "Mathematics"       2018)
   (list "Ted"       "Tedly"    1480618 "GWSS"              2019)
   (list "Urkle"     "Andersen" 1681805 "Anthropology"      2018)
   (list "Violet"    "Teal"     1493989 "Economics"         2019)
   (list "Xerxes"    "Homer"    1547425 "Economics"         2019)
   (list "Yvonne"    "Stein"    1748611 "Sociology"         2018)
   (list "Zed"       "Rebel"    1540899 "Computer Science"  2017)
   ))

(define simulated-students-by-id
  (vector
   (list "Heather"   "Jones"    1046860 "Classics"          2021)
   (list "Ira"       "Jackson"  1070103 "Political Science" 2022)
   (list "Sam"       "Sky"      1085519 "Mathematics"       2018)
   (list "Maria"     "Moody"    1168059 "Computer Science"  2020)
   (list "Bob"       "Smith"    1170605 "Mathematics"       2020)
   (list "Ned"       "Black"    1177023 "Russian"           2018)
   (list "Paula"     "Hall"     1218704 "Psychology"        2018)
   (list "Fred"      "Stone"    1260057 "Linguistics"       2018)
   (list "Charlotte" "Davis"    1304091 "Independent"       2018)
   (list "Erin"      "Anderson" 1320727 "Philosophy"        2019)
   (list "Amy"       "Zevon"    1336804 "Computer Science"  2019)
   (list "Leo"       "Levens"   1399810 "English"           2019)
   (list "Danielle"  "Jones"    1472662 "Undeclared"        2021)
   (list "Ted"       "Tedly"    1480618 "GWSS"              2019)
   (list "Janet"     "Smith"    1488985 "Chemistry"         2019)
   (list "Violet"    "Teal"     1493989 "Economics"         2019)
   (list "Zed"       "Rebel"    1540899 "Computer Science"  2017)
   (list "Devon"     "Smith"    1546921 "Computer Science"  2018)
   (list "Xerxes"    "Homer"    1547425 "Economics"         2019)
   (list "Rebecca"   "Davis"    1658200 "Biology"           2020)
   (list "Greg"      "Jones"    1668280 "Classics"          2020)
   (list "Quentin"   "Smith"    1679081 "Art History"       2018)
   (list "Urkle"     "Andersen" 1681805 "Anthropology"      2018)
   (list "Yvonne"    "Stein"    1748611 "Sociology"         2018)
   (list "Karla"     "Hill"     1821167 "Psychology"        2018)
   (list "Otto"      "White"    1908656 "Chinese"           2019)
   ))

(define simulated-students-by-year
  (vector
   (list "Zed"       "Rebel"    1540899 "Computer Science"  2017)
   (list "Ned"       "Black"    1177023 "Russian"           2018)
   (list "Yvonne"    "Stein"    1748611 "Sociology"         2018)
   (list "Karla"     "Hill"     1821167 "Psychology"        2018)
   (list "Paula"     "Hall"     1218704 "Psychology"        2018)
   (list "Charlotte" "Davis"    1304091 "Independent"       2018)
   (list "Fred"      "Stone"    1260057 "Linguistics"       2018)
   (list "Quentin"   "Smith"    1679081 "Art History"       2018)
   (list "Sam"       "Sky"      1085519 "Mathematics"       2018)
   (list "Urkle"     "Andersen" 1681805 "Anthropology"      2018)
   (list "Devon"     "Smith"    1546921 "Computer Science"  2018)
   (list "Ted"       "Tedly"    1480618 "GWSS"              2019)
   (list "Leo"       "Levens"   1399810 "English"           2019)
   (list "Otto"      "White"    1908656 "Chinese"           2019)
   (list "Janet"     "Smith"    1488985 "Chemistry"         2019)
   (list "Violet"    "Teal"     1493989 "Economics"         2019)
   (list "Xerxes"    "Homer"    1547425 "Economics"         2019)
   (list "Erin"      "Anderson" 1320727 "Philosophy"        2019)
   (list "Amy"       "Zevon"    1336804 "Computer Science"  2019)
   (list "Rebecca"   "Davis"    1658200 "Biology"           2020)
   (list "Greg"      "Jones"    1668280 "Classics"          2020)
   (list "Bob"       "Smith"    1170605 "Mathematics"       2020)
   (list "Maria"     "Moody"    1168059 "Computer Science"  2020)
   (list "Heather"   "Jones"    1046860 "Classics"          2021)
   (list "Danielle"  "Jones"    1472662 "Undeclared"        2021)
   (list "Ira"       "Jackson"  1070103 "Political Science" 2022)
   ))

;;; Value:
;;;   small-primes
;;; Type:
;;;   vector of integers
;;; Contents:
;;;   All of the prime numbers less than 1000, arranged in increasing order.
(define small-primes
  (vector 2 3 5 7 11 13 17 19 23 29 31 37
          41 43 47 53 59 61 67 71 73 79 83 89 97
          101 103 107 109 113 127 131 137 139 149
          151 157 163 167 173 179 181 191 193 197 199
          211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293
          307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397
          401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499
          503 509 521 523 541 547 557 563 569 571 577 587 593 599
          601 607 613 617 619 631 641 643 647 653 659 661 673 677 683 691
          701 709 719 727 733 739 743 751 757 761 769 773 787 797
          809 811 821 823 827 829 839 853 857 859 863 877 881 883 887
          907 911 919 929 937 941 947 953 967 971 977 983 991 997))

;;; Procedure:
;;;   binary-search
;;; Parameters:
;;;   vec, a vector to search
;;;   get-key, a procedure of one parameter that, given a data item,
;;;     returns the key of a data item
;;;   less-equal?, a binary predicate that tells us whether or not
;;;     one key is less than or equal to another
;;;   key, a key we're looking for
;;; Purpose:
;;;   Search vec for a value whose key matches key.
;;; Produces:
;;;   match, a number.
;;; Preconditions:
;;;   * The vector is "sorted".  That is,
;;;     (less-equal? (get-key (vector-ref vec i))
;;;                  (get-key (vector-ref vec (+ i 1))))
;;;     holds for all reasonable i.
;;;   * The get-key procedure can be applied to all values in the vector.
;;;   * The less-equal? procedure can be applied to all pairs of keys
;;;     in the vector (and to the supplied key).
;;;   * The less-equal? procedure is transitive.  That is, if
;;;     (less-equal? a b) and (less-equal? b c) then it must
;;;     be that (less-equal? a c).
;;;   * If two values are equal, then each may precede the other.
;;;   * Similarly, if two values may each precede the other, then
;;;     the two values are equal.
;;; Postconditions:
;;;   * If vector contains no element whose key matches key, match is -1.
;;;   * If vec contains an element whose key equals key, match is the
;;;     index of one such value.  That is, key is
;;;       (get-key (vector-ref vec match))
(define binary-search
  (lambda (vec get-key less-equal? key)
    ; Search a portion of the vector from lower-bound to upper-bound
    (let search-portion ([lower-bound 0]
                         [upper-bound (- (vector-length vec) 1)])
      ; If the portion is empty
      (if (> lower-bound upper-bound)
          ; Indicate the value cannot be found
          -1
          ; Otherwise, identify the middle point, the element at that 
          ; point and the key of that element.
          (let* ([point-of-division (quotient (+ lower-bound upper-bound) 2)]
                 [separating-element (vector-ref vec point-of-division)]
                 [sep-elt-key (get-key separating-element)])
            (cond
              ; If the middle key equals the value, we use the middle value.
              [(and (less-equal? key sep-elt-key)
                    (less-equal? sep-elt-key key))
               point-of-division]
              ; If the middle key is too large, look in the left half
              ; of the region.
              [(less-equal? key sep-elt-key)
               (search-portion lower-bound (- point-of-division 1))]
              ; Otherwise, the middle key must be too small, so look 
              ; in the right half of the region.
              [else
               (search-portion (+ point-of-division 1) upper-bound)]))))))

;;; Procedure:
;;;   lookup-by-first-name
;;; Parameters:
;;;   directory, a list of student info entries
;;;   first-name, a string
;;; Purpose:
;;;   Find the entry associated with name.
;;; Produces:
;;;   entry, a student info entry
;;; Preconditions:
;;;   * Each element of directory is a student info entry (a list of
;;;     first name, last name, student id, major, and graduation year).
;;;   * directory is arranged alphabetically by name, from alphabetically
;;;     first to alphabetically last.  That is,
;;;     (string-ci<=? (car (vector-ref directory i))
;;;                   (car (vector-ref directory (+ i 1))))
;;;     for all reasonable i.
;;;   * No two entries have the same name.
;;; Postconditions:
;;;   If there is an i s.t. (car (vector-ref directory i)) is first-name, then
;;;     entry is (vector-ref objects i)
;;;   Otherwise, entry is #f
(define lookup-by-first-name
  (lambda (directory first-name)
    (let ([index (binary-search directory car string-ci<=? first-name)])
      (if (= index -1)
          #f
          (vector-ref directory index)))))

;;; Procedure:
;;;   vector-sorted?
;;; Parameters:
;;;   vec, a vector
;;;   get-key, a procedure that extracts keys from the elements of vec
;;;   less-equal?, a procedure that compares keys
;;; Purpose:
;;;   Determine if vec is sorted by key
;;; Produces:
;;;   is-sorted?, a Boolean
;;; Preconditions:
;;;   get-key should be applicable to any value in vec.
;;;   less-equal? should be applicable to any two values returned by get-key.
;;; Postconditions:
;;;   If, for all reasonable i,
;;;     (less-equal? (get-key (vector-ref vec i))
;;;                   (get-key (vector-ref vec (+ i 1))))
;;;     then is-sorted is #t.
;;;   Otherwise,
;;;     is-sorted is #f.
(define vector-sorted?
  (lambda (vec get-key less-equal?)
    (let ([veclen (vector-length vec)])
      (letrec ([kernel (lambda (i)
                         (or (= i (- veclen 1))
                             (and (less-equal? (get-key (vector-ref vec i))
                                               (get-key (vector-ref vec (+ i 1))))
                                  (kernel (+ i 1)))))])
        (kernel 0)))))
