MC logo

CS 231 Assignment 3 Key


CS 231 Programming Assignments

Below is a key for assignment 3.
[Download]
;
; This file provides some simplification of the expressions produced by
; the derivative system.
;

; ** Main simplifier **
; This just calls a single simplifier for each of sum and product, but
; sends some parameters to adapt it.  It also does an extra step for
; products which changes products containing 0 to 0.
(defun simplify (E)
    (cond
        ((is-sum E) (simpl '+ 'collapse-dup-terms 'is-sum 
                              (lambda (x) (cons '+ x)) 0 E))
        ((is-product E)
            (kill-zero (simpl '* 'identity 'is-product
                              (lambda (x) (cons '* x)) 1 E)))
        (t E)
    )
)

; ** Zero killer
; If the argument is a product and contains zero, return zero.  Else
; return the argument.
(defun kill-zero (E)
    (cond
        ((not (is-product E)) E)
        ((null (remove-if (lambda (x) (not (equal 0 x))) E)) E)
        (t 0)
    )
)

; ** General simplifier
; This works for either sums or products.  It takes the function which
; identifies sub-expressions of the same type, the function which adds the
; correct operator symbol to the front of the list, the identity for the
; operation, and the expression.  It gets the parts (terms or factors),
; simplifies each one, flattens the list (which removes sublists of
; the same type, as (+ 5 (+ 6 7)) to + (+ 5 6 7)), removes the identity
; (which is 0 or 1), then does some cleanup and adds the operator symbol
; back to the list.
(defun simpl (the-operator merge-op is-same-type add-operator identity E)
    (let* 
        (
            (parts (cdr E))
            (simparts (mapcar 'simplify parts))
            (flatparts (flatten is-same-type (funcall merge-op simparts)))
            (combined (const-combine the-operator identity flatparts))
        )
        (proper add-operator identity combined)
    )
)

; This combines the constants in the list of items (terms or factors),
; moves the combined constant to the front, and omits it if it is the identity.
(defun const-combine (the-operator identity items)
    (let*
        (
            (nonconst (remove-if 'is-constant items))
            (constval
                (reduce the-operator
                    (remove-if (lambda (x) (not (is-constant x))) items)
                )
            )
        )
        (if  (not (equal identity constval))
            (cons constval nonconst)
            nonconst
        )
    )
)

; This function collects all itmes similar to the first into a (* ) sublist.
; If there are no items similar to the first, the list is unchagned.
(defun collect-like-first (items)
    (let*
        (
            (headitem (car items))
            (tailitems (cdr items))
            (we-like (lambda (x) (equal x headitem)))
            (we-dont-like (lambda (x) (not (equal x headitem))))
            (like-these (remove-if we-dont-like tailitems))
            (dont-like-these (remove-if we-like tailitems))
        )
        (if (null like-these) 
            items
            (cons
                (cons '*
                    (const-combine '* 1
                        (flatten 'is-product
                            (list (+ 1 (length like-these)) headitem)
                        )
                    )
                )
                dont-like-these
            )
        )
    )
)


;
; This function looks in a sum for repeated terms, and changes them into
; a multiplication by a constant.  It ignores constants, as they will be
; taken care of by const-combine.
(defun collapse-dup-terms (terms)
    (cond
        ((null terms) ())
        ((is-constant (car terms))
            (cons (car terms) (collapse-dup-terms (cdr terms)))
        )
        (t
            (let*
                ((collected (collect-like-first terms)))
                (cons (car collected) (collapse-dup-terms (cdr collected)))
            )
        )
    )
)

; Here is the code for flatten.  It takes sublists of the same type and
; merges them into the whole list, as (* (* a b 2) 3 (* 5 2)) to
; (* a b 2 3 5 2)
(defun flatten (is-same items)
    (cond 
        ((null items) ())
        ((funcall is-same (car items))
            (append (cdr (car items)) (flatten is-same (cdr items)))  )
        (t (cons (car items) (flatten is-same (cdr items))))
    )
)

; A clean-up step to avoid stuff like (*) and (+ x).  Its basic function is
; to add the operator back to the front of a list of simplified parts,
; but it checks and avoids producing expressions with zero or one part.
(defun proper (add-operator identity items)
    (cond
        ((null items) identity)
        ((null (cdr items)) (car items))
        (t (funcall add-operator items))
    )
)