;; Caltech CS1 Fall 2007
;; Scheme code used in Lecture 8 (10/24/07)
;; mvanier@cs.caltech.edu

;; Complex numbers without compound data
(define (complex-add-real ar ai br bi)
  (+ ar br))
(define (complex-add-imag ar ai br bi)
  (+ ai bi))

;; use
(define (arbitrary-complex-function ar ai br bi)
  (define cr (complex-add-real ar ai br bi))
  (define ci (complex-add-imag ar ai br bi))
  ;; Here in body we could use (cr, ci) as the
  ;; result of the complex addition.
  )

;; on to multiply...
(define (complex-multiply-real ar ai br bi)
  (- (* ar br) (* ai bi)))
(define (complex-multiply-imag ar ai br bi)
  (+ (* ar bi) (* ai br)))

;; foo(A,B,C) = A+B*C where A, B, C are complex numbers
(define (foo-real ar ai br bi cr ci)
  (complex-add-real ar ai
                    (complex-multiply-real br bi cr ci)
                    (complex-multiply-imag br bi cr ci)))
(define (foo-imag ar ai br bi cr ci)
  (complex-add-imag ar ai
                    (complex-multiply-real br bi cr ci)
                    (complex-multiply-imag br bi cr ci)))

;; Compound data in Scheme:
;; cons -- "glues" two data items together
;; car -- extracts first
;; cdr -- extracts second
;; property:
;;  (car (cons a b)) == a
;;  (cdr (cons a b)) == b
;; displayed in Scheme as dotted pair: (a . b)
(cons 3 4)
; result: (3 . 4)
(define a-pair (cons 3 4))
(car a-pair)
; result: 3
(cdr a-pair)
; result: 4
[Turn page over]

;; Complex numbers with data abstraction
;; Base level of abstraction 
;;  represent C = a + bi (i = sqrt(-1))

;; Constructor (makes complex number from numbers).
(define (make-complex real imaginary) 
  (cons real imaginary))

;; Accessors to extract the real and imaginary components.
(define (get-real complex) (car complex))
(define (get-imag complex) (cdr complex))

;; Complex arithmetic in terms of the abstraction
(define (complex-add a b)
  (make-complex
    (+ (get-real a) (get-real b))    ;; new real
    (+ (get-imag a) (get-imag b))))  ;; new imaginary

(define (complex-multiply a b)
  (make-complex
    (- (* (get-real a) (get-real b)) 
       (* (get-imag a) (get-imag b)))   ;; new real
    (+ (* (get-real a) (get-imag b))
       (* (get-imag a) (get-real b))))) ;; new imaginary

(define (complex-magnitude a)
  (sqrt (+ (square (get-real a)) 
           (square (get-imag a)))))

;; Once we have operators, use those for higher
;; level operations --- higher level operations
;; on complex numbers don't even need to know how
;; to take apart and construct complex numbers!
;; foo(A,B,C) = A+B*C
(define (foo a b c)
  (complex-add a (complex-multiply b c)))

;; consider representing a complex 
;;   quadratic equation:
;; Q(x) = A*x2 + B*x + C

;; Constructor:
(define (make-quadratic a b c)
  (cons a (cons b c)))
;; Accessors:
(define (get-a quad) (car quad))
(define (get-b quad) (car (cdr quad)))
(define (get-c quad) (cdr (cdr quad)))

;; Define useful operators in terms of 
;; abstract representation:
(define (evaluate-quadratic quad point)
  (complex-add
   (complex-add
    (complex-multiply (get-a quad)
                      (complex-multiply point point))
    (complex-multiply (get-b quad) point))
   point))
