Advertisement
timothy235

sicp-2-5-3-the-symbolic-algebra-program

Feb 22nd, 2017
159
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Racket 36.42 KB | None | 0 0
  1. #lang racket
  2.  
  3. ;; This is the complete symbolic algebra program from section 2.5.3, including
  4. ;; polynomials in more than one variable, a hierarchy of variables and coercion,
  5. ;; and rational functions, as outlined in the exercises.
  6.  
  7. ;;;;;;;;;;;;;;;;;;;;;;
  8. ;; GLOBAL VARIABLES ;;
  9. ;;;;;;;;;;;;;;;;;;;;;;
  10.  
  11. ;; Specify the output representation for polynomial term lists here.
  12. (define TERMLIST-OUTPUT-TYPE 'dense) ; 'dense or 'sparse
  13.  
  14. ;; Only allow these variables in polynomials.
  15. (define VARIABLE-LIST '(x y z))
  16. (define HIGHEST-VARIABLE (first VARIABLE-LIST))
  17. (define LOWEST-VARIABLE (last VARIABLE-LIST))
  18.  
  19. ;; Only simplify the results of these operations.
  20. (define SIMPLIFY-LIST '(add sub mul div expo
  21.                           sqroot square
  22.                           arctan cosine sine
  23.                           re-part im-part mag-part ang-part
  24.                           first-term constant-term
  25.                           ))
  26. (define (can-simplify? op) (member op SIMPLIFY-LIST))
  27.  
  28. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  29. ;; PROCEDURE TABLES AND VARIABLE DICTIONARIES ;;
  30. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  31.  
  32. ;; procedure table for generic operations
  33. (define op-table (make-hash))
  34. (define (put op tag-list proc)
  35.   (hash-set! op-table (cons op tag-list) proc))
  36. (define (can-apply? op tag-list)
  37.   (member (cons op tag-list) (hash-keys op-table)))
  38. (define (get op tag-list) (hash-ref op-table (cons op tag-list)))
  39.  
  40. ;; procedure table for type coercion operations
  41. (define coercion-table (make-hash))
  42. (define (put-project type proc)
  43.   (hash-set! coercion-table (cons 'project type) proc))
  44. (define (can-project? arg)
  45.   (member (cons 'project (type-tag arg)) (hash-keys coercion-table)))
  46. (define (project arg)
  47.   ((hash-ref coercion-table (cons 'project (type-tag arg))) arg))
  48. ;; raising the type
  49. (define (put-raise type proc)
  50.   (hash-set! coercion-table (cons 'raise type) proc))
  51. (define (can-raise? arg)
  52.   (member (cons 'raise (type-tag arg)) (hash-keys coercion-table)))
  53. (define (raise arg)
  54.   ((hash-ref coercion-table (cons 'raise (type-tag arg))) arg))
  55.  
  56. ;; variable dictionaries
  57. (define next-higher-variable (make-hash))
  58. (define next-lower-variable (make-hash))
  59. (define (install-variable-dictionaries)
  60.   (define (loop var)
  61.     (cond [(eq? var LOWEST-VARIABLE) 'done]
  62.           [else
  63.             (define next-lower (second (member var VARIABLE-LIST)))
  64.             (hash-set! next-lower-variable var next-lower)
  65.             (hash-set! next-higher-variable next-lower var)
  66.             (loop next-lower)]))
  67.   (loop HIGHEST-VARIABLE))
  68. (install-variable-dictionaries)
  69.  
  70. (define (next-higher var) (hash-ref next-higher-variable var))
  71. (define (next-lower var) (hash-ref next-lower-variable var))
  72.  
  73. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  74. ;; APPLY-GENERIC AND HELPER FUNCTIONS ;;
  75. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  76.  
  77. ;; procedures for handling type tags
  78. (define (attach-tag type-tag datum)
  79.   (cond [(exact-integer? datum) datum]
  80.         [(inexact-real? datum) datum]
  81.         [else (cons type-tag datum)]))
  82. (define (type-tag datum)
  83.   (cond [(exact-integer? datum) 'integer]
  84.         [(inexact-real? datum) 'real]
  85.         [(pair? datum) (first datum)]
  86.         [else (error "Bad tagged datum -- TYPE-TAG:" datum)]))
  87. (define (contents datum)
  88.   (cond [(exact-integer? datum) datum]
  89.         [(inexact-real? datum) datum]
  90.         [(pair? datum) (cdr datum)]
  91.         [else (error "Bad tagged datum -- CONTENTS:" datum)]))
  92.  
  93. ;; type coercion and simplification
  94. (define (simplify arg)
  95.   ; Simplify arg to the lowest possible correct type.
  96.   (cond [(can-project? arg)
  97.          (define projected-arg (project arg))
  98.          (if (equ? arg (raise projected-arg))
  99.            (simplify projected-arg)
  100.            arg)]
  101.         [else arg]))
  102. (define (highest-type tag-list)
  103.   ; Return the highest type in tag-list.
  104.   (define (loop type arg)
  105.     (cond [(can-raise? arg)
  106.            (define raised-arg (raise arg))
  107.            (define raised-type (type-tag raised-arg))
  108.            (if (member raised-type tag-list)
  109.              (loop raised-type raised-arg)
  110.              (loop type raised-arg))]
  111.           [else type]))
  112.   (loop 'integer 1))
  113.  
  114. (define (coerce arg target-type)
  115.   ; Raise arg until it has type target-type. Assume type of arg <= target-type.
  116.   (if (equal? (type-tag arg) target-type)
  117.     arg
  118.     (coerce (raise arg) target-type)))
  119. (define (coerce-all args target-type)
  120.   ; Coerce all arguments to the target type.
  121.   (map (lambda (arg) (coerce arg target-type)) args))
  122.  
  123. ;; the generic application procedure
  124. (define (apply-generic op . args)
  125.   ; Dispatch by type.
  126.   (define (simplify-result datum)
  127.     (if (can-simplify? op)
  128.       (simplify datum)
  129.       datum))
  130.   (define type-tags (map type-tag args))
  131.   (cond [(can-apply? op type-tags)
  132.          (simplify-result (apply (get op type-tags) (map contents args)))]
  133.         [(andmap (lambda (type) (equal? type (first type-tags))) type-tags)
  134.          (error "No method available -- APPLY-GENERIC:" op type-tags)]
  135.         [else
  136.           (define coerced-args (coerce-all args (highest-type type-tags)))
  137.           (simplify-result (apply (get op (map type-tag coerced-args))
  138.                                   (map contents coerced-args)))]))
  139.  
  140. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  141. ;; THE GENERIC OPERATIONS ;;
  142. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  143.  
  144. ;; constructors and selectors
  145. (define (make-integer a) ((get 'make 'integer) a))
  146. (define (make-rational-number n d) ((get 'make 'rational-number) n d))
  147. (define (make-rational-function n d) ((get 'make 'rational-function) n d))
  148. (define (make-real x) ((get 'make 'real) x))
  149. ;; complex numbers
  150. (define (make-complex-from-real-imag x y)
  151.   ((get 'make-from-real-imag 'complex) x y))
  152. (define (make-complex-from-mag-ang r a)
  153.   ((get 'make-from-mag-ang 'complex) r a))
  154. (define (re-part z) (apply-generic 're-part z))
  155. (define (im-part z) (apply-generic 'im-part z))
  156. (define (mag-part z) (apply-generic 'mag-part z))
  157. (define (ang-part z) (apply-generic 'ang-part z))
  158. ;; polynomials
  159. (define (make-poly-from-dense-termlist var term-list)
  160.   ((get 'make-from-dense-termlist `(polynomial ,var)) term-list))
  161. (define (make-poly-from-sparse-termlist var term-list)
  162.   ((get 'make-from-sparse-termlist `(polynomial ,var)) term-list))
  163.  
  164. ;; generic operations
  165. (define (=zero? x) (apply-generic '=zero? x))
  166. (define (absolute x) (apply-generic 'absolute x))
  167. (define (add x y) (apply-generic 'add x y))
  168. (define (arctan y x) (apply-generic 'arctan y x))
  169. (define (constant-term p) (apply-generic 'constant-term p))
  170. (define (cosine x) (apply-generic 'cosine x))
  171. (define (div x y) (apply-generic 'div x y))
  172. (define (equ? x y) (apply-generic 'equ? x y))
  173. (define (expo x y) (apply-generic 'expo x y))
  174. (define (first-term p) (apply-generic 'first-term p))
  175. (define (greatest-common-divisor x y)
  176.   (apply-generic 'greatest-common-divisor x y))
  177. (define (mul x y) (apply-generic 'mul x y))
  178. (define (polynomial-division p1 p2)
  179.   (apply-generic 'polynomial-division p1 p2))
  180. (define (reduce x y) (apply-generic 'reduce x y))
  181. (define (sine x) (apply-generic 'sine x))
  182. (define (sqroot x) (apply-generic 'sqroot x))
  183. (define (square x) (apply-generic 'square x))
  184. (define (sub x y) (apply-generic 'sub x y))
  185.  
  186. ;;;;;;;;;;;;;;;
  187. ;; INTEGERS  ;;
  188. ;;;;;;;;;;;;;;;
  189.  
  190. (define (install-integer-package)
  191.   ;; internal procedures
  192.   (define (make-integer a)
  193.     (define int (floor a))
  194.     (if (exact? int)
  195.       int
  196.       (inexact->exact int)))
  197.   (define (=zero-integer? a) (= a 0))
  198.   (define (gcd-integer a b)
  199.     (if (= b 0) a (gcd-integer b (remainder a b))))
  200.   (define (reduce-integer n d)
  201.     (define g (gcd-integer n d))
  202.     (list (/ n g) (/ d g)))
  203.   (define arctan (compose make-real atan))
  204.   (define cosine (compose make-real cos))
  205.   (define sine (compose make-real sin))
  206.   (define sqroot (compose make-real sqrt))
  207.   ;; coercion procedures
  208.   (define (raise a) (make-rational-number a 1))
  209.   (put-raise 'integer raise)
  210.   ;; interface to the rest of the system
  211.   (put 'make 'integer make-integer)
  212.   (put '=zero? '(integer) =zero-integer?)
  213.   (put 'absolute '(integer) abs)
  214.   (put 'add '(integer integer) +)
  215.   (put 'arctan '(integer integer) arctan)
  216.   (put 'cosine '(integer) cosine)
  217.   (put 'div '(integer integer) make-rational-number)
  218.   (put 'equ? '(integer integer) =)
  219.   (put 'expo '(integer integer) expt)
  220.   (put 'greatest-common-divisor '(integer integer) gcd-integer)
  221.   (put 'mul '(integer integer) *)
  222.   (put 'reduce '(integer integer) reduce-integer)
  223.   (put 'sine '(integer) sine)
  224.   (put 'sqroot '(integer) sqroot)
  225.   (put 'square '(integer) sqr)
  226.   (put 'sub '(integer integer) -)
  227.   )
  228. (install-integer-package)
  229.  
  230. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  231. ;; RATIONAL NUMBERS AND RATIONAL FUNCTIONS ;;
  232. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  233.  
  234. (define (install-rational-package)
  235.  
  236.   ;; internal procedures
  237.   (define (make-rat n d) (reduce n d))
  238.   (define (numer x) (first x))
  239.   (define (denom x) (second x))
  240.   (define (=zero-rat? x) (=zero? (numer x)))
  241.   (define (equ-rat? x y) (equ? (mul (numer x) (denom y))
  242.                                (mul (denom x) (numer y))))
  243.   (define (add-rat x y)
  244.     (make-rat (add (mul (numer x) (denom y))
  245.                    (mul (numer y) (denom x)))
  246.               (mul (denom x) (denom y))))
  247.   (define (sub-rat x y)
  248.     (make-rat (sub (mul (numer x) (denom y))
  249.                    (mul (numer y) (denom x)))
  250.               (mul (denom x) (denom y))))
  251.   (define (mul-rat x y)
  252.     (make-rat (mul (numer x) (numer y))
  253.               (mul (denom x) (denom y))))
  254.   (define (div-rat x y)
  255.     (make-rat (mul (numer x) (denom y))
  256.               (mul (denom x) (numer y))))
  257.  
  258.   ;; procedures for rational numbers only
  259.   (define (absolute x) (make-real (abs (/ (numer x) (denom x)))))
  260.   (define (arctan y x) (make-real (atan (/ (numer y) (denom y)))))
  261.   (define (cosine x) (make-real (cos (/ (numer x) (denom x)))))
  262.   (define (expo-ratnum x y) (make-real (expt (/ (numer x) (denom x))
  263.                                              (/ (numer y) (denom y)))))
  264.   (define (sine x) (make-real (sin (/ (numer x) (denom x)))))
  265.   (define (square x) (make-rat (sqr (numer x)) (sqr (denom x))))
  266.   (define (sqroot x) (make-real (sqrt (/ (numer x) (denom x)))))
  267.  
  268.   ;; procedures for rational functions only
  269.   (define (expo-ratfunc x n)
  270.     (cond [(and (integer? n) (positive? n))
  271.            (if (= n 1)
  272.              x
  273.              (mul-rat x (expo-ratfunc x (sub1 n))))]
  274.           [else
  275.             (error "Exponent must be a positive integer -- EXPO-RATFUNC:" x n)]))
  276.  
  277.   ;; coercion procedures for rational numbers
  278.   (define (project-rat x) (make-integer (floor (/ (numer x) (denom x)))))
  279.   (define (raise-rat x) (make-real (/ (numer x) (denom x))))
  280.   (put-project 'rational-number (compose project-rat contents))
  281.   (put-raise 'rational-number (compose raise-rat contents))
  282.  
  283.   ;; interface to the rest of the system for rational numbers
  284.   (define (tag-as-number x) (attach-tag 'rational-number x))
  285.   (put 'make 'rational-number
  286.        (compose tag-as-number make-rat))
  287.   (put '=zero? '(rational-number) =zero-rat?)
  288.   (put 'absolute '(rational-number) absolute)
  289.   (put 'add '(rational-number rational-number)
  290.        (compose tag-as-number add-rat))
  291.   (put 'arctan '(rational-number rational-number) arctan)
  292.   (put 'cosine '(rational-number) cosine)
  293.   (put 'div '(rational-number rational-number)
  294.        (compose tag-as-number div-rat))
  295.   (put 'equ? '(rational-number rational-number) equ-rat?)
  296.   (put 'expo '(rational-number rational-number) expo-ratnum)
  297.   (put 'mul '(rational-number rational-number)
  298.        (compose tag-as-number mul-rat))
  299.   (put 'sine '(rational-number) sine)
  300.   (put 'sqroot '(rational-number) sqroot)
  301.   (put 'square '(rational-number) (compose tag-as-number square))
  302.   (put 'sub '(rational-number rational-number)
  303.        (compose tag-as-number sub-rat))
  304.  
  305.   ;; interface to the rest of the system for rational functions
  306.   (define (tag-as-function x) (attach-tag 'rational-function x))
  307.   (put 'make 'rational-function
  308.        (compose tag-as-function make-rat))
  309.   (put '=zero? '(rational-function) =zero-rat?)
  310.   (put 'add '(rational-function rational-function)
  311.        (compose tag-as-function add-rat))
  312.   (put 'div '(rational-function rational-function)
  313.        (compose tag-as-function div-rat))
  314.   (put 'equ? '(rational-function rational-function) equ-rat?)
  315.   (put 'expo '(rational-function integer)
  316.        (compose tag-as-function expo-ratfunc))
  317.   (put 'mul '(rational-function rational-function)
  318.        (compose tag-as-function mul-rat))
  319.   (put 'sub '(rational-function rational-function)
  320.        (compose tag-as-function sub-rat))
  321.   )
  322. (install-rational-package)
  323.  
  324. ;;;;;;;;;;;;;;;;;;
  325. ;; REAL NUMBERS ;;
  326. ;;;;;;;;;;;;;;;;;;
  327.  
  328. (define (install-real-package)
  329.   ;; internal procedures
  330.   (define (make-real x) ; x is a racket number or has lower type
  331.     (cond [(pair? x) (raise x)]
  332.           [(exact? x) (exact->inexact x)]
  333.           [else x]))
  334.   ; Account for floating-point error.
  335.   (define (=zero-real? x) (< (abs x) 0.000000001))
  336.   (define (equ-real? x y) (< (abs (- x y)) 0.000000001))
  337.   ;; coercion procedures
  338.   (define (project-real x)
  339.     (make-rational-number (make-integer (floor (* x 1000000000))) 1000000000))
  340.   (define (raise-real x) (make-complex-from-real-imag x 0))
  341.   (put-project 'real project-real)
  342.   (put-raise 'real raise-real)
  343.   ;; interface to the rest of the system
  344.   (put 'make 'real make-real)
  345.   (put '=zero? '(real) =zero-real?)
  346.   (put 'absolute '(real) abs)
  347.   (put 'add '(real real) +)
  348.   (put 'arctan '(real real) atan)
  349.   (put 'cosine '(real) cos)
  350.   (put 'div '(real real) /)
  351.   (put 'equ? '(real real) =)
  352.   (put 'expo '(real real) expt)
  353.   (put 'mul '(real real) *)
  354.   (put 'sine '(real) sin)
  355.   (put 'sqroot '(real) sqrt)
  356.   (put 'square '(real) sqr)
  357.   (put 'sub '(real real) -)
  358.   )
  359. (install-real-package)
  360.  
  361. ;;;;;;;;;;;;;;;;;;;;;
  362. ;; COMPLEX NUMBERS ;;
  363. ;;;;;;;;;;;;;;;;;;;;;
  364.  
  365. (define (install-complex-package)
  366.  
  367.   ;; rectangular coordinates
  368.   (define (install-rectangular-package)
  369.     ;; internal procedures
  370.     (define (make-from-real-imag x y) (list x y))
  371.     (define (re-part z) (first z))
  372.     (define (im-part z) (second z))
  373.     (define (make-from-mag-ang r a)
  374.       (list (mul r (cosine a))
  375.             (mul r (sine a))))
  376.     (define (mag-part z)
  377.       (sqroot (add (square (re-part z))
  378.                    (square (im-part z)))))
  379.     (define (ang-part z) (arctan (im-part z) (re-part z)))
  380.     ;; interface to the rest of the system
  381.     (define (tag z) (attach-tag 'rectangular z))
  382.     (put 'make-from-mag-ang 'rectangular (compose tag make-from-mag-ang))
  383.     (put 'make-from-real-imag 'rectangular (compose tag make-from-real-imag))
  384.     (put 're-part '(rectangular) re-part)
  385.     (put 'im-part '(rectangular) im-part)
  386.     (put 'mag-part '(rectangular) mag-part)
  387.     (put 'ang-part '(rectangular) ang-part)
  388.     )
  389.   (install-rectangular-package)
  390.  
  391.   ;; polar coordinates
  392.   (define (install-polar-package)
  393.     ;; internal procedures
  394.     (define (make-from-mag-ang r a) (list r a))
  395.     (define (mag-part z) (first z))
  396.     (define (ang-part z) (second z))
  397.     (define (make-from-real-imag x y)
  398.       (list (sqroot (add (square x) (square y)))
  399.             (arctan y x)))
  400.     (define (re-part z) (mul (mag-part z) (cosine (ang-part z))))
  401.     (define (im-part z) (mul (mag-part z) (sine (ang-part z))))
  402.     ;; interface to the rest of the system
  403.     (define (tag x) (attach-tag 'polar x))
  404.     (put 'make-from-mag-ang 'polar (compose tag make-from-mag-ang))
  405.     (put 'make-from-real-imag 'polar (compose tag make-from-real-imag))
  406.     (put 're-part '(polar) re-part)
  407.     (put 'im-part '(polar) im-part)
  408.     (put 'mag-part '(polar) mag-part)
  409.     (put 'ang-part '(polar) ang-part)
  410.     )
  411.   (install-polar-package)
  412.  
  413.   ;; imported procedures from rectangular and polar subpackages
  414.   (define make-from-real-imag (get 'make-from-real-imag 'rectangular))
  415.   (define make-from-mag-ang (get 'make-from-mag-ang 'polar))
  416.  
  417.   ;; internal complex number procedures
  418.   (define (=zero-complex? z) ; account for floating-point error
  419.     (and (< (absolute (re-part z)) 0.000000001)
  420.          (< (absolute (im-part z)) 0.000000001)))
  421.   (define (equ? z1 z2) ; account for floating-point error
  422.     (and (< (absolute (sub (re-part z1) (re-part z2))) 0.000000001)
  423.          (< (absolute (sub (im-part z1) (im-part z2))) 0.000000001)))
  424.   (define (add-complex z1 z2)
  425.     (make-from-real-imag (add (re-part z1) (re-part z2))
  426.                          (add (im-part z1) (im-part z2))))
  427.   (define (sub-complex z1 z2)
  428.     (make-from-real-imag (sub (re-part z1) (re-part z2))
  429.                          (sub (im-part z1) (im-part z2))))
  430.   (define (mul-complex z1 z2)
  431.     (make-from-mag-ang (mul (mag-part z1) (mag-part z2))
  432.                        (add (ang-part z1) (ang-part z2))))
  433.   (define (div-complex z1 z2)
  434.     (make-from-mag-ang (div (mag-part z1) (mag-part z2))
  435.                        (sub (ang-part z1) (ang-part z2))))
  436.   (define (expo-complex z1 z2)
  437.     (define w (expt (+ (make-real (re-part z1))
  438.                        (* (make-real (im-part z1)) 0+i))
  439.                     (+ (make-real (re-part z2))
  440.                        (* (make-real (im-part z2)) 0+i))))
  441.     (make-from-real-imag (real-part w) (imag-part w)))
  442.   ;; coercion procedures
  443.   (define (project-complex z) (make-real (re-part z)))
  444.   (define (raise-complex z)
  445.     (make-poly-from-dense-termlist LOWEST-VARIABLE (list (simplify z))))
  446.   (put-project 'complex project-complex)
  447.   (put-raise 'complex raise-complex)
  448.   ;; interface to the rest of the system
  449.   (define (tag z) (attach-tag 'complex z))
  450.   (put 'make-from-mag-ang 'complex
  451.        (compose tag make-from-mag-ang))
  452.   (put 'make-from-real-imag 'complex
  453.        (compose tag make-from-real-imag))
  454.   (put '=zero? '(complex) =zero-complex?)
  455.   (put 'add '(complex complex) (compose tag add-complex))
  456.   (put 'ang-part '(complex) ang-part)
  457.   (put 'div '(complex complex) (compose tag div-complex))
  458.   (put 'equ? '(complex complex) equ?)
  459.   (put 'expo '(complex complex) (compose tag expo-complex))
  460.   (put 'im-part '(complex) im-part)
  461.   (put 'mag-part '(complex) mag-part)
  462.   (put 'mul '(complex complex) (compose tag mul-complex))
  463.   (put 're-part '(complex) re-part)
  464.   (put 'sub '(complex complex) (compose tag sub-complex))
  465.   )
  466. (install-complex-package)
  467.  
  468. ;;;;;;;;;;;;;;;;;
  469. ;; POLYNOMIALS ;;
  470. ;;;;;;;;;;;;;;;;;
  471.  
  472. (define (install-polynomial-package)
  473.  
  474.   ;; term list representations
  475.  
  476.   ;; sparse term lists
  477.   (define (install-sparse-termlist-package)
  478.     ;; constructors and selectors
  479.     (define (make-term order coeff) (list order coeff))
  480.     (define (order term) (first term))
  481.     (define (coeff term) (second term))
  482.     (define (the-empty-termlist) empty)
  483.     (define empty-termlist? null?)
  484.     (define (first-term L)
  485.       (if (empty-termlist? L)
  486.         (make-term 0 0)
  487.         (first L)))
  488.     (define (rest-terms L) (cdr L))
  489.     (define (dense->sparse DL)
  490.       (cond [(null? DL) (the-empty-termlist)]
  491.             [(=zero? (first DL)) (dense->sparse (cdr DL))]
  492.             [else (cons (make-term (- (length DL) 1)
  493.                                    (first DL))
  494.                         (dense->sparse (cdr DL)))]))
  495.     ;; procedures for generic operations
  496.     (define (adjoin-term term L)
  497.       (if (=zero? (coeff term))
  498.         L
  499.         (cons term L)))
  500.     (define (constant-term L)
  501.       (cond [(empty-termlist? L)
  502.              (make-term 0 0)]
  503.             [else
  504.               (define last-term (last L))
  505.               (if (zero? (order last-term))
  506.                 last-term
  507.                 (make-term 0 0))]))
  508.     (define (negate-terms L)
  509.       (map (lambda (term)
  510.              (make-term (order term)
  511.                         (mul -1 (coeff term))))
  512.            L))
  513.     (define (reduce-coefficients L) ; divide all coeffs by their gcd
  514.       (define (list-of-coefficients term-list)
  515.         ; Return a list of coefficients in no particular order.
  516.         (foldr (lambda (term a-list)
  517.                  (cons (second term) a-list))
  518.               empty
  519.                term-list))
  520.       (define gcf (foldr greatest-common-divisor
  521.                          0
  522.                          (list-of-coefficients L)))
  523.       (map (lambda (term)
  524.              (make-term (order term)
  525.                         (div (coeff term) gcf)))
  526.            L))
  527.     ;; interface to the rest of the system
  528.     (define (tag-as-sparse x) (attach-tag 'sparse x))
  529.     (define (tag-as-term x) (attach-tag 'term x))
  530.     (put 'make-from-dense-termlist 'sparse
  531.          (compose tag-as-sparse dense->sparse))
  532.     (put 'make-from-sparse-termlist 'sparse tag-as-sparse)
  533.     (put 'adjoin-term '(term sparse)
  534.          (compose tag-as-sparse adjoin-term))
  535.     (put 'constant-term '(sparse)
  536.          (compose tag-as-term constant-term))
  537.     (put 'first-term '(sparse)
  538.          (compose tag-as-term first-term))
  539.     (put 'negate-terms '(sparse)
  540.          (compose tag-as-sparse negate-terms))
  541.     (put 'reduce-coefficients '(sparse)
  542.          (compose tag-as-sparse reduce-coefficients))
  543.     (put 'rest-terms '(sparse)
  544.          (compose tag-as-sparse rest-terms))
  545.     )
  546.   (install-sparse-termlist-package)
  547.  
  548.   ;; dense term lists
  549.   (define (install-dense-termlist-package)
  550.     ;; internal procedures
  551.     (define (make-term order coeff) (list order coeff))
  552.     (define (order term) (first term))
  553.     (define (coeff term) (second term))
  554.     (define (the-empty-termlist) empty)
  555.     (define empty-termlist? null?)
  556.     (define (first-term L)
  557.       (if (empty-termlist? L)
  558.         (make-term 0 0)
  559.         (make-term (- (length L) 1)
  560.                    (first L))))
  561.     (define (rest-terms L) (cdr L))
  562.     (define (sparse->dense SL)
  563.       (define (list-of-zeroes n) (for/list ([i (in-range n)]) 0))
  564.       (cond [(empty? SL)
  565.              (the-empty-termlist)]
  566.             [else
  567.               (define first-term (first SL))
  568.               (cond [(=zero? (coeff first-term))
  569.                      (sparse->dense (rest SL))]
  570.                     [(empty? (rest SL)) ; only one term in SL
  571.                      (cons (coeff first-term)
  572.                            (list-of-zeroes (order first-term)))]
  573.                     [else
  574.                       (define second-term (second SL))
  575.                       (append (cons (coeff first-term)
  576.                                     (list-of-zeroes (- (order first-term)
  577.                                                        (order second-term)
  578.                                                        1)))
  579.                               (sparse->dense (rest SL)))])]))
  580.     (define (adjoin-term term L) ; order >= length L
  581.       (define (loop term-list)
  582.         (if (> (order term) (length term-list))
  583.           (loop (cons 0 term-list))
  584.           (cons (coeff term) term-list)))
  585.       (if (=zero? (coeff term))
  586.         L
  587.         (loop L)))
  588.     (define (constant-term L)
  589.       (if (empty-termlist? L)
  590.         (make-term 0 0)
  591.         (make-term 0 (last L))))
  592.     (define (negate-terms L)
  593.       (map (lambda (coefficient)
  594.              (mul -1 coefficient))
  595.            L))
  596.     (define (reduce-coefficients L) ; divide all coeffs by their gcd
  597.       (define gcf (foldr greatest-common-divisor 0 L))
  598.       (map (lambda (coeff)
  599.              (div coeff gcf))
  600.            L))
  601.     ;; interface to the rest of the system
  602.     (define (tag-as-dense x) (attach-tag 'dense x))
  603.     (define (tag-as-term x) (attach-tag 'term x))
  604.     (put 'make-from-dense-termlist 'dense tag-as-dense)
  605.     (put 'make-from-sparse-termlist 'dense
  606.          (compose tag-as-dense sparse->dense))
  607.     (put 'adjoin-term '(term dense)
  608.          (compose tag-as-dense adjoin-term))
  609.     (put 'constant-term '(dense)
  610.          (compose tag-as-term constant-term))
  611.     (put 'first-term '(dense)
  612.          (compose tag-as-term first-term))
  613.     (put 'negate-terms '(dense)
  614.          (compose tag-as-dense negate-terms))
  615.     (put 'reduce-coefficients '(dense)
  616.          (compose tag-as-dense reduce-coefficients))
  617.     (put 'rest-terms '(dense)
  618.          (compose tag-as-dense rest-terms))
  619.     )
  620.   (install-dense-termlist-package)
  621.  
  622.   ;; imported procedures from the term list subpackages
  623.   (define make-from-dense-termlist
  624.     (get 'make-from-dense-termlist TERMLIST-OUTPUT-TYPE))
  625.   (define make-from-sparse-termlist
  626.     (get 'make-from-sparse-termlist TERMLIST-OUTPUT-TYPE))
  627.  
  628.   ;; term and term list operations
  629.   (define (make-term order coeff) (list 'term order coeff))
  630.   (define (order term) (second term))
  631.   (define (coeff term) (third term))
  632.   (define (rest-terms L) (apply-generic 'rest-terms L))
  633.   (define (the-empty-termlist) (list TERMLIST-OUTPUT-TYPE))
  634.   (define (empty-termlist? L) (null? (contents L)))
  635.   (define (=zero-termlist? L)
  636.     (or (empty-termlist? L)
  637.         (and (=zero? (coeff (first-term L)))
  638.              (=zero-termlist? (rest-terms L)))))
  639.   (define (reduce-coefficients L)
  640.     (apply-generic 'reduce-coefficients L))
  641.   (define (adjoin-term term L) (apply-generic 'adjoin-term term L))
  642.   (define (negate-terms L) (apply-generic 'negate-terms L))
  643.   (define (add-terms L1 L2)
  644.     (cond [(empty-termlist? L1) L2]
  645.           [(empty-termlist? L2) L1]
  646.           [else
  647.             (define t1 (first-term L1))
  648.             (define t2 (first-term L2))
  649.             (cond [(> (order t1) (order t2))
  650.                    (adjoin-term t1
  651.                                 (add-terms (rest-terms L1) L2))]
  652.                   [(< (order t1) (order t2))
  653.                    (adjoin-term t2
  654.                                 (add-terms L1 (rest-terms L2)))]
  655.                   [else (adjoin-term
  656.                           (make-term (order t1)
  657.                                      (add (coeff t1) (coeff t2)))
  658.                           (add-terms (rest-terms L1)
  659.                                      (rest-terms L2)))])]))
  660.   (define (sub-terms L1 L2) (add-terms L1 (negate-terms L2)))
  661.   (define (equ-termlist? L1 L2)
  662.     (=zero-termlist? (sub-terms L1 L2)))
  663.   (define (mul-term-by-all-terms t1 L)
  664.     (cond [(empty-termlist? L)
  665.            (the-empty-termlist)]
  666.           [else
  667.             (define t2 (first-term L))
  668.             (adjoin-term
  669.               (make-term (+ (order t1) (order t2))
  670.                          (mul (coeff t1) (coeff t2)))
  671.               (mul-term-by-all-terms t1 (rest-terms L)))]))
  672.   (define (mul-terms L1 L2)
  673.     (if (empty-termlist? L1)
  674.       (the-empty-termlist)
  675.       (add-terms (mul-term-by-all-terms (first-term L1) L2)
  676.                  (mul-terms (rest-terms L1) L2))))
  677.   (define (div-terms L1 L2)
  678.     (cond [(empty-termlist? L1)
  679.            (list (the-empty-termlist) (the-empty-termlist))]
  680.           [else
  681.             (define t1 (first-term L1))
  682.             (define t2 (first-term L2))
  683.             (cond [(> (order t2) (order t1))
  684.                    (list (the-empty-termlist) L1)]
  685.                   [else
  686.                     (define divisor-term
  687.                       (make-term (- (order t1) (order t2))
  688.                                  (div (coeff t1) (coeff t2))))
  689.                     (define rest-of-result
  690.                       (div-terms (sub-terms L1
  691.                                             (mul-term-by-all-terms divisor-term
  692.                                                                     L2))
  693.                                  L2))
  694.                     (list (adjoin-term divisor-term (first rest-of-result))
  695.                           (second rest-of-result))])]))
  696.   (define (divisor-termlist L1 L2) (first (div-terms L1 L2)))
  697.   (define (remainder-termlist L1 L2) (second (div-terms L1 L2)))
  698.   (define (expo-terms L n)
  699.     (cond [(positive? n)
  700.            (if (= n 1)
  701.              L
  702.              (mul-terms L (expo-terms L (sub1 n))))]
  703.           [else
  704.             (error "Exponent must be a positive integer -- EXPO-TERMS:" L n)]))
  705.   (define (gcd-terms a b)
  706.     (if (empty-termlist? b)
  707.       a
  708.       (gcd-terms b (remainder-termlist a b))))
  709.   (define (pseudo-remainder-termlist L1 L2)
  710.     ; Clear denominators from remainder-termlist.
  711.     (remainder-termlist (mul-term-by-all-terms
  712.                           (make-term 0 (expt (coeff (first-term L2))
  713.                                              (+ 1
  714.                                                 (order (first-term L1))
  715.                                                 (- (order (first-term L2))))))
  716.                           L1)
  717.                         L2))
  718.   (define (pseudo-gcd-terms a b)
  719.     ; Return a gcd term list with integer coefficients.
  720.     (if (empty-termlist? b)
  721.       a
  722.       (pseudo-gcd-terms b (pseudo-remainder-termlist a b))))
  723.   (define (reduce-terms a b)
  724.     (define (same-sign? L1 L2)
  725.       (positive? (make-real
  726.                    (re-part
  727.                      (coerce (mul (coeff (first-term L1))
  728.                                   (coeff (first-term L2)))
  729.                              'complex)))))
  730.     (define (fix-signs L1 L2)
  731.       ; Ensure the leading coefficient of L1/L2 is the same as that of a/b.
  732.       (cond [(and (same-sign? a L1) (not (same-sign? b L2)))
  733.              (list L1 (negate-terms L2))]
  734.             [(and (not (same-sign? a L1)) (same-sign? b L2))
  735.              (list (negate-terms L1) L2)]
  736.             [(and (not (same-sign? a L1)) (not (same-sign? b L2)))
  737.              (list (negate-terms L1) (negate-terms L2))]
  738.             [else (list L1 L2)]))
  739.     (define pseudo-gcf (pseudo-gcd-terms a b))
  740.     (define (integerizing-factor L1 L2)
  741.       (expt (coeff (first-term pseudo-gcf))
  742.             (+ 1 (max (order (first-term L1)) (order (first-term L2)))
  743.                (- (order (first-term pseudo-gcf))))))
  744.     (define (clear-denominators L)
  745.       (mul-term-by-all-terms (make-term 0 (integerizing-factor a b))
  746.                              L))
  747.     (apply fix-signs
  748.            (map (lambda (term-list) (reduce-coefficients
  749.                                       (divisor-termlist
  750.                                         (clear-denominators term-list)
  751.                                         pseudo-gcf)))
  752.                 (list a b))))
  753.   ;; polynomial operations
  754.   (define (make-poly var term-list)
  755.     (attach-tag `(polynomial ,var) term-list))
  756.   (define (variable poly) (second (first poly)))
  757.   (define (term-list poly) (rest poly))
  758.  
  759.   ;; coercion operations
  760.   ; Coercion procedures act on tagged polynomials.
  761.   (define (project-poly-to-complex p)
  762.     (coerce (coeff (constant-term (term-list p))) 'complex))
  763.   (define (project-poly-to-poly p)
  764.     (coerce (coeff (constant-term (term-list p)))
  765.             `(polynomial ,(next-lower (variable p)))))
  766.   (define (raise-poly p)
  767.     (make-poly-from-dense-termlist (next-higher (variable p)) (list p)))
  768.   (define (install-coercion-procedures)
  769.     (define (loop var) ; assume there is more than one variable
  770.       (cond [(eq? var HIGHEST-VARIABLE)       ; start of the loop
  771.              (put-project `(polynomial ,var) project-poly-to-poly)
  772.              (loop (next-lower var))]
  773.             [(eq? var LOWEST-VARIABLE)        ; end of the loop
  774.              (put-project `(polynomial ,var) project-poly-to-complex)
  775.              (put-raise `(polynomial ,var) raise-poly)
  776.              'done]
  777.             [else                               ; middle of the loop
  778.               (put-project `(polynomial ,var) project-poly-to-poly)
  779.               (put-raise `(polynomial ,var) raise-poly)
  780.               (loop (next-lower var))]))
  781.     (if (eq? HIGHEST-VARIABLE LOWEST-VARIABLE) ; only one variable
  782.       (put-project `(polynomial ,LOWEST-VARIABLE) project-poly-to-complex)
  783.       (loop HIGHEST-VARIABLE)))
  784.   (install-coercion-procedures)
  785.  
  786.   ;; interface to the rest of the system
  787.   ; Generic procedures act on the contents of polynomials, ie term lists.
  788.   (define (install-generic-procedures)
  789.     (define (loop var)
  790.       (put 'make-from-dense-termlist `(polynomial ,var)
  791.            (compose (curry make-poly var) make-from-dense-termlist))
  792.       (put 'make-from-sparse-termlist `(polynomial ,var)
  793.            (compose (curry make-poly var) make-from-sparse-termlist))
  794.       (put '=zero? `((polynomial ,var)) =zero-termlist?)
  795.       (put 'equ? `((polynomial ,var) (polynomial ,var)) equ-termlist?)
  796.       (put 'add `((polynomial ,var) (polynomial ,var))
  797.            (compose (curry make-poly var) add-terms))
  798.       (put 'sub `((polynomial ,var) (polynomial ,var))
  799.            (compose (curry make-poly var) sub-terms))
  800.       (put 'mul `((polynomial ,var) (polynomial ,var))
  801.            (compose (curry make-poly var) mul-terms))
  802.       (put 'expo `((polynomial ,var) integer)
  803.            (compose (curry make-poly var) expo-terms))
  804.       (put 'first-term `((polynomial ,var)) first-term)
  805.       (put 'constant-term `((polynomial ,var)) constant-term)
  806.       (if (eq? var LOWEST-VARIABLE)
  807.         (begin
  808.           (put 'polynomial-division
  809.                `((polynomial ,LOWEST-VARIABLE)
  810.                  (polynomial ,LOWEST-VARIABLE))
  811.                (lambda (L1 L2)
  812.                  (map (curry make-poly LOWEST-VARIABLE)
  813.                       (div-terms L1 L2))))
  814.           (put 'greatest-common-divisor
  815.                `((polynomial ,LOWEST-VARIABLE)
  816.                  (polynomial ,LOWEST-VARIABLE))
  817.                ; return a gcd with reduced integer coefficients
  818.                (compose (curry make-poly LOWEST-VARIABLE)
  819.                         reduce-coefficients
  820.                         pseudo-gcd-terms))
  821.           (put 'reduce
  822.                `((polynomial ,LOWEST-VARIABLE)
  823.                  (polynomial ,LOWEST-VARIABLE))
  824.                (lambda (L1 L2) (map (curry make-poly LOWEST-VARIABLE)
  825.                                     (reduce-terms L1 L2))))
  826.           )
  827.         (loop (next-lower var))))
  828.     (loop HIGHEST-VARIABLE))
  829.   (install-generic-procedures)
  830.   )
  831. (install-polynomial-package)
  832.  
  833. ;;;;;;;;;;;
  834. ;; TESTS ;;
  835. ;;;;;;;;;;;
  836.  
  837. ;; NUMBERS
  838.  
  839. (=zero? (sub (make-complex-from-real-imag (make-rational-number 1 2)
  840.                                           0.75)
  841.              (make-complex-from-real-imag 0.5
  842.                                           (make-rational-number 3 4))))
  843. ;; #t
  844. (equ? (expo (make-complex-from-mag-ang 1 1) pi)
  845.       -1) ; e ^ (i * pi) = -1
  846. ;; #t
  847. (mul 0.25 (make-complex-from-real-imag 4 0))
  848. ;; 1
  849.  
  850. ;; POLYNOMIALS IN DIFFERENT VARIABLES
  851.  
  852. (define p (make-poly-from-dense-termlist 'x '(1 2 3)))
  853. (define q (make-poly-from-dense-termlist 'y '(4 5 6)))
  854. (add p q)
  855. ;; '((polynomial x) dense 1 2 ((polynomial y) dense 4 5 9))
  856. (sub p q)
  857. ;; '((polynomial x) dense 1 2 ((polynomial y) dense -4 -5 -3))
  858. (mul p q)
  859. ;; '((polynomial x)
  860.   ;; dense
  861.   ;; ((polynomial y) dense 4 5 6)
  862.   ;; ((polynomial y) dense 8 10 12)
  863.   ;; ((polynomial y) dense 12 15 18))
  864.  
  865. ;; POLYNOMIALS IN THE SAME VARIABLE
  866.  
  867. (define p1 (make-poly-from-dense-termlist 'z '(1 1)))
  868. (define p2 (make-poly-from-dense-termlist 'z '(1 0 1)))
  869. (mul p1 p2)
  870. ;; '((polynomial z) dense 1 1 1 1)
  871. (expo p1 3)
  872. ;; '((polynomial z) dense 1 3 3 1)
  873. (reduce (mul p1 p2) (expo p1 3))
  874. ;; '(((polynomial z) dense 1 0 1) ((polynomial z) dense 1 2 1))
  875. (polynomial-division
  876.   (make-poly-from-dense-termlist 'z '(32 0 0 0 0 -243))
  877.   (make-poly-from-dense-termlist 'z '(2 -3)))
  878. ;; '(((polynomial z) dense 16 24 36 54 81) ((polynomial z) dense))
  879.  
  880. ;; RATIONAL FUNCTIONS
  881.  
  882. (define r1 (make-rational-function
  883.              (make-poly-from-dense-termlist 'z '(1 3 3 1))
  884.              (make-poly-from-dense-termlist 'z '(1 -2 1)))) ; (x+1)^3/(x-1)^2
  885. r1
  886. ;; '(rational-function
  887.   ;; ((polynomial z) dense 1 3 3 1)
  888.   ;; ((polynomial z) dense 1 -2 1))
  889. (define r2 (make-rational-function
  890.              (make-poly-from-dense-termlist 'z '(1 -3 3 -1))
  891.              (make-poly-from-dense-termlist 'z '(1 2 1)))) ; (x-1)^3/(x+1)^2
  892. r2
  893. ;; '(rational-function
  894.   ;; ((polynomial z) dense 1 -3 3 -1)
  895.   ;; ((polynomial z) dense 1 2 1))
  896. (add r1 r2)
  897. ;; '(rational-function
  898.   ;; ((polynomial z) dense 1 0 10 0 5 0)
  899.   ;; ((polynomial z) dense 1 0 -2 0 1))
  900. (mul r1 r2)
  901. ;; '(rational-function ((polynomial z) dense 1 0 -1) ((polynomial z) dense 1))
  902. (div r1 r2)
  903. ;; '(rational-function
  904.   ;; ((polynomial z) dense 1 5 10 10 5 1)
  905.   ;; ((polynomial z) dense 1 -5 10 -10 5 -1))
  906.  
  907. ;; WITH SPARSE OUTPUT
  908.  
  909. (define s (make-poly-from-dense-termlist
  910.             'y
  911.             `(1
  912.               2.0
  913.               ,(make-rational-number 6 2)
  914.               ,(make-complex-from-real-imag 4 0)
  915.               ,(make-complex-from-mag-ang -5 pi))))
  916. (expo s 6) ; (y^4 + 2*y^3 + 3*y^2 + 4*y + 5) ^ 6
  917. ;; '((polynomial y)
  918.   ;; sparse
  919.   ;; (24 1)
  920.   ;; (23 12)
  921.   ;; (22 78)
  922.   ;; (21 364)
  923.   ;; (20 1365)
  924.   ;; (19 4332)
  925.   ;; (18 11974)
  926.   ;; (17 29376)
  927.   ;; (16 64818)
  928.   ;; (15 129740)
  929.   ;; (14 236958)
  930.   ;; (13 396516)
  931.   ;; (12 609389)
  932.   ;; (11 860772)
  933.   ;; (10 1117050)
  934.   ;; (9 1329584)
  935.   ;; (8 1446498)
  936.   ;; (7 1430532)
  937.   ;; (6 1276546)
  938.   ;; (5 1016220)
  939.   ;; (4 709125)
  940.   ;; (3 422500)
  941.   ;; (2 206250)
  942.   ;; (1 75000)
  943.   ;; (0 15625))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement