Skip to content

2.91

; A univariate polynomial can be divided by another one to produce a polynomial 
; quotient and a polynomial remainder. For example,
;
; $\frac{x^5 - 1}{x^2 - 1} = x^3 + x$, remainder $x-1$
;
; Division can be performed via long division. That is, divide the highest-order 
; term of the dividend by the highest-order term of the divisor. The result is the 
; first term of the quotient. Next, multiply the result by the divisor, subtract 
; that from the dividend, and produce the rest of the answer by recursively dividing
; the difference by the divisor. Stop when the order of the divisor exceeds the order
; of the dividend and declare the dividend to be the remainder. Also, if the dividend
; ever becomes zero, return zero as both quotient and remainder.
;
; We can design a div-poly procedure on the model of add- poly and mul-poly. The 
; procedure checks to see if the two polys have the same variable. If so, div-poly 
; strips off the variable and passes the problem to div-terms, which performs the 
; division operation on term lists. div-poly finally reattaches the variable to the 
; result supplied by div-terms. It is convenient to design div-terms to compute both
; the quotient and the remainder of a division. div-terms can take two term lists as
; arguments and return a list of the quotient term list and the remainder term list.
;
; Complete the following definition of div-terms by filling in the missing expressions. 
; Use this to implement div-poly, which takes two polys as arguments and returns a 
; list of the quotient and remainder polys.

; Add the following to `polynomial` package
(define (div-terms L1 L2) 
    (if (empty-termlist? L1)
        (list (the-empty-termlist) (the-empty-termlist)) 
        (let ((t1 (first-term L1))
              (t2 (first-term L2)))
            (if (> (order t2) (order t1))
                (list (the-empty-termlist) L1)
                (let ((new-c (div (coeff t1) (coeff t2)))
                      (new-o (- (order t1) (order t2)))) 
                    (let ((rest-of-result
                          (div-terms
                            (add-terms
                                L1
                                (negate-terms
                                    (mul-term-by-all-terms
                                        (make-term new-o new-c)
                                        L2)))
                            L2))) 
                        (cons
                            (adjoin-term
                                (make-term new-o new-c)
                                (car rest-of-result))
                            (cdr rest-of-result))))))))

; Redefining the polynomial package
(define (install-polynomial-package)
    ;; internal procedures
    ;; representation of poly
    (define (make-poly variable term-list) (cons variable term-list))
    (define (variable p) (car p))
    (define (term-list p) (cdr p))
    ; ⟨procedures same-variable? and variable? from section 2.3.2⟩
    (define (variable? x) (symbol? x))
    (define (same-variable? v1 v2)
        (and (variable? v1) (variable? v2) (eq? v1 v2)))

    ;; representation of terms and term lists
    ;; ⟨procedures adjoin-term . . . coeff from text below⟩

    ;; Add
    (define (add-poly p1 p2)
        (if (same-variable? (variable p1) (variable p2))
            (make-poly 
                (variable p1)
                (add-terms (term-list p1) (term-list p2)))
            (error "Polys not in same var: ADD-POLY" (list p1 p2))))
    (define (add-terms L1 L2)
        (cond ((empty-termlist? L1) L2)
              ((empty-termlist? L2) L1)
              (else
                (let ((t1 (first-term L1))
                      (t2 (first-term L2)))
                    (cond ((> (order t1) (order t2))
                           (adjoin-term
                            t1
                            (add-terms (rest-terms L1) L2)))
                          ((< (order t1) (order t2))
                           (adjoin-term
                            t2
                            (add-terms L1 (rest-terms L2))))
                          (else
                            (adjoin-term
                                (make-term
                                    (order t1)
                                    (add (coeff t1) (coeff t2)))
                                (add-terms 
                                    (rest-terms L1)
                                    (rest-terms L2)))))))))

    ;; Multiply
    (define (mul-poly p1 p2)
        (if (same-variable? (variable p1) (variable p2))
            (make-poly 
                (variable p1)
                (mul-terms (term-list p1) (term-list p2)))
            (error "Polys not in same var: MUL-POLY" (list p1 p2))))
    (define (mul-terms L1 L2)
        (if (empty-termlist? L1)
            (the-empty-termlist)
            (add-terms
                (mul-term-by-all-terms (first-term L1) L2)
                (mul-terms (rest-terms) L2))))
    (define (mul-term-by-all-terms t1 L)
        (if (empty-termlist? L)
            (the-empty-termlist)
            (let ((t2 (first-term L)))
                (adjoin-term
                    (make-term
                        (+ (order t1) (order t2))
                        (mul (coeff t1) (coeff t2)))
                    (mul-term-by-all-terms
                        t1
                        (rest-terms L))))))

    (define (poly-zero? term-list)
        (if (empty-termlist? term-list)
            #t
            (and (=zero? (coeff (first-term term-list)))
                 (poly-zero? (rest-terms term-list)))))
    ;; Subtraction
    (define (negate-terms term-list)
        (if (empty-termlist? term-list)
            the-empty-termlist
            (adjoin-term
                (make-term 
                    (order (first-term term-list)) 
                    (negate (coeff (first-term term-list))))
                (negate-terms (rest-terms term-list)))))
    (define (sub-poly p1 p2)
        (if (same-variable? (variable p1) (variable p2))
            (make-poly 
                (variable p1)
                (add-terms (term-list p1) (negate-terms (term-list p2))))
            (error "Polys not in same var: SUB-POLY" (list p1 p2))))

    ;; Division
    (define (div-terms L1 L2) 
        (if (empty-termlist? L1)
            (list (the-empty-termlist) (the-empty-termlist)) 
            (let ((t1 (first-term L1))
                  (t2 (first-term L2)))
                (if (> (order t2) (order t1))
                    (list (the-empty-termlist) L1)
                    (let ((new-c (div (coeff t1) (coeff t2)))
                          (new-o (- (order t1) (order t2)))) 
                        (let ((rest-of-result
                              (div-terms
                                (add-terms
                                    L1
                                    (negate-terms 
                                        (mul-term-by-all-terms
                                            (make-term new-o new-c)
                                            L2)))
                                L2))) 
                            (list
                                (adjoin-term
                                    (make-term new-o new-c)
                                    (car rest-of-result))
                                (cadr rest-of-result))))))))
    (define (div-poly p1 p2)
        (if (same-variable? (variable p1) (variable p2))
            (let ((ans (div-terms (term-list p1)
                                  (term-list p2))))
                (list (make-poly (variable p1)
                                 (car ans))
                      (make-poly (variable p1)
                                 (cadr ans))))
            (error "Polys not in same var: DIV-POLY" (list p1 p2))))

    ;; interface to rest of the system
    (define (tag p) (attach-tag 'polynomial p))
    (put '=zero? '(polynomial) (lambda (p) (poly-zero? (term-list p))))
    (put 'add '(polynomial polynomial)
        (lambda (p1 p2) (tag (add-poly p1 p2))))
    (put 'mul '(polynomial polynomial)
        (lambda (p1 p2) (tag (mul-poly p1 p2))))
    (put 'div '(polynomial polynomial)
        (lambda (p1 p2) (tag (div-poly p1 p2))))
    (put 'make 'polynomial
        (lambda (var terms) (tag (make-poly var terms))))
    (put 'negate '(polynomial)
        (lambda (p) 
            (make-polynomial 
                (variable p)
                (negate-terms (term-list p)))))
    (put 'sub '(polynomial polynomial)
        (lambda (p1 p2) (tag (sub-poly p1 p2))))
    'done)

;; representation of terms
(define (adjoin-term term term-list)
    (if (=zero? (coeff term))
        term-list
        (cons term term-list)))
(define (the-empty-termlist) '())
(define (first-term term-list) (car term-list))
(define (rest-terms term-list) (cdr term-list))
(define (empty-termlist? term-list) (null? term-list))
(define (make-term order coeff) (list order coeff))
(define (order term) (car term))
(define (coeff term) (cadr term))

(define (make-polynomial var terms)
    ((get 'make 'polynomial) var terms))

; Testing
(load "arithmetic-package.scm")

(install-polynomial-package)

(define p1 
    (make-polynomial 
        'x
        (list (make-term  5  (make-scheme-number 1))
              (make-term  0  (make-scheme-number -1))))) ; x^5 - 1

(define p2 
    (make-polynomial 
        'x
        (list (make-term  2  (make-scheme-number 1))
              (make-term  0  (make-scheme-number -1))))) ; x^2 - 1

(div p1 p2)
; Note: This returns an error, couldn't get this working :/