Building a system for symbolic differentiation

Similar documents
Building a system for symbolic differentiation

Using Symbols in Expressions (1) evaluate sub-expressions... Number. ( ) machine code to add

An Explicit-Continuation Metacircular Evaluator

A Brief Introduction to Scheme (II)

6.001: Structure and Interpretation of Computer Programs

6.001 Notes: Section 8.1

6.184 Lecture 4. Interpretation. Tweaked by Ben Vandiver Compiled by Mike Phillips Original material by Eric Grimson

Scheme in Scheme: The Metacircular Evaluator Eval and Apply

Documentation for LISP in BASIC

6.945 Adventures in Advanced Symbolic Programming

regsim.scm ~/umb/cs450/ch5.base/ 1 11/11/13

Fall Semester, The Metacircular Evaluator. Today we shift perspective from that of a user of computer langugaes to that of a designer of

6.001 Notes: Section 15.1

CS450 - Structure of Higher Level Languages

Why do we need an interpreter? SICP Interpretation part 1. Role of each part of the interpreter. 1. Arithmetic calculator.

6.037 Lecture 4. Interpretation. What is an interpreter? Why do we need an interpreter? Stages of an interpreter. Role of each part of the interpreter

Functional Programming. Pure Functional Programming

CS61A Midterm 2 Review (v1.1)

Computer Science 21b (Spring Term, 2015) Structure and Interpretation of Computer Programs. Lexical addressing

;; definition of function, fun, that adds 7 to the input (define fun (lambda (x) (+ x 7)))

Syntactic Sugar: Using the Metacircular Evaluator to Implement the Language You Want

Deferred operations. Continuations Structure and Interpretation of Computer Programs. Tail recursion in action.

4.2 Variations on a Scheme -- Lazy Evaluation

Announcements. The current topic: Scheme. Review: BST functions. Review: Representing trees in Scheme. Reminder: Lab 2 is due on Monday at 10:30 am.

SCHEME 10 COMPUTER SCIENCE 61A. July 26, Warm Up: Conditional Expressions. 1. What does Scheme print? scm> (if (or #t (/ 1 0)) 1 (/ 1 0))

Project 2: Scheme Interpreter

Streams, Delayed Evaluation and a Normal Order Interpreter. CS 550 Programming Languages Jeremy Johnson

Summer 2017 Discussion 10: July 25, Introduction. 2 Primitives and Define

Discussion 12 The MCE (solutions)

CS61A Summer 2010 George Wang, Jonathan Kotker, Seshadri Mahalingam, Eric Tzeng, Steven Tang

CS 314 Principles of Programming Languages

An introduction to Scheme

CSc 520 Principles of Programming Languages

Project 5 - The Meta-Circular Evaluator

Simplifying Logical Formulas

Introduction to Scheme

University of Massachusetts Lowell

Below are example solutions for each of the questions. These are not the only possible answers, but they are the most common ones.

Project 5 - The Meta-Circular Evaluator

CS 314 Principles of Programming Languages. Lecture 16

User-defined Functions. Conditional Expressions in Scheme

Procedural abstraction SICP Data abstractions. The universe of procedures forsqrt. Procedural abstraction example: sqrt

CS 61A Interpreters, Tail Calls, Macros, Streams, Iterators. Spring 2019 Guerrilla Section 5: April 20, Interpreters.

C311 Lab #3 Representation Independence: Representation Independent Interpreters

Normal Order (Lazy) Evaluation SICP. Applicative Order vs. Normal (Lazy) Order. Applicative vs. Normal? How can we implement lazy evaluation?


CS 61A, Fall, 2002, Midterm #2, L. Rowe. 1. (10 points, 1 point each part) Consider the following five box-and-arrow diagrams.

Interpreters and Tail Calls Fall 2017 Discussion 8: November 1, 2017 Solutions. 1 Calculator. calc> (+ 2 2) 4

6.001 Notes: Section 6.1

Lecture #24: Programming Languages and Programs

Building up a language SICP Variations on a Scheme. Meval. The Core Evaluator. Eval. Apply. 2. syntax procedures. 1.

;;; Determines if e is a primitive by looking it up in the primitive environment. ;;; Define indentation and output routines for the output for

Modern Programming Languages. Lecture LISP Programming Language An Introduction

Sample Final Exam Questions

CS61A Discussion Notes: Week 11: The Metacircular Evaluator By Greg Krimer, with slight modifications by Phoebus Chen (using notes from Todd Segal)

Functional Programming. Pure Functional Languages

15 Unification and Embedded Languages in Lisp

Scheme Quick Reference

6.001 Notes: Section 17.5

SCHEME AND CALCULATOR 5b

Scheme. Functional Programming. Lambda Calculus. CSC 4101: Programming Languages 1. Textbook, Sections , 13.7

Lisp Basic Example Test Questions

An Explicit Continuation Evaluator for Scheme

From Syntactic Sugar to the Syntactic Meth Lab:

Lecture Notes on Lisp A Brief Introduction

PROFESSOR: Well, yesterday we learned a bit about symbolic manipulation, and we wrote a rather stylized

Scheme Quick Reference

Scheme: Data. CS F331 Programming Languages CSCE A331 Programming Language Concepts Lecture Slides Monday, April 3, Glenn G.

Fall 2017 Discussion 7: October 25, 2017 Solutions. 1 Introduction. 2 Primitives

Fall 2018 Discussion 8: October 24, 2018 Solutions. 1 Introduction. 2 Primitives

Repetition Through Recursion

6.001, Spring Semester, 1998, Final Exam Solutions Your Name: 2 Part c: The procedure eval-until: (define (eval-until exp env) (let ((return (eval-seq

MORE SCHEME. 1 What Would Scheme Print? COMPUTER SCIENCE MENTORS 61A. October 30 to November 3, Solution: Solutions begin on the following page.

CSE 341 Lecture 16. More Scheme: lists; helpers; let/let*; higher-order functions; lambdas

CSSE 304 Assignment #13 (interpreter milestone #1) Updated for Fall, 2018

Resources matter. Orders of Growth of Processes. R(n)= (n 2 ) Orders of growth of processes. Partial trace for (ifact 4) Partial trace for (fact 4)

RACKET BASICS, ORDER OF EVALUATION, RECURSION 1

Typed Scheme: Scheme with Static Types

SCHEME 7. 1 Introduction. 2 Primitives COMPUTER SCIENCE 61A. October 29, 2015

Homework 1. Notes. What To Turn In. Unix Accounts. Reading. Handout 3 CSCI 334: Spring, 2017

CS 314 Principles of Programming Languages

Administrivia. Simple data types

CS 360 Programming Languages Interpreters

SCHEME 8. 1 Introduction. 2 Primitives COMPUTER SCIENCE 61A. March 23, 2017

6.001 Notes: Section 4.1

Type Inference and Type Habitation (5/10/2004)

Homework 1. Reading. Problems. Handout 3 CSCI 334: Spring, 2012

CS61A Notes Disc 11: Streams Streaming Along

FUNKCIONÁLNÍ A LOGICKÉ PROGRAMOVÁNÍ 3. LISP: ZÁKLADNÍ FUNKCE, POUŽÍVÁNÍ REKURZE,

Principles of Programming Languages

LECTURE 16. Functional Programming

INTERPRETERS 8. 1 Calculator COMPUTER SCIENCE 61A. November 3, 2016

6.001 Notes: Section 5.1

Lists in Lisp and Scheme

ALISP interpreter in Awk

Typed Racket: Racket with Static Types

Spring 2018 Discussion 7: March 21, Introduction. 2 Primitives

6.037 Lecture 7B. Scheme Variants Normal Order Lazy Evaluation Streams

Functional Programming - 2. Higher Order Functions

Streams. CS21b: Structure and Interpretation of Computer Programs Spring Term, 2004

Transcription:

Computer Science 21b Structure and Interpretation of Computer Programs Building a system for symbolic differentiation Selectors, constructors and predicates: (constant? e) Is e a constant? (variable? e) Is e a variable? (same-variable? v 1 v 2 ) Are v 1 and v 2 the same variable? (sum? e) Is e a sum? (product? e) Is e a product? (addend e) Addend of the sum e. (augend e) Augend of the sum e. (multiplier e) Multiplier of the product e. (multiplicand e) Multiplicand of the product e. (make-constant c) Construct the constant c. (make-sum a 1 a 2 ) Construct the sum of a 1 and a 2. (make-product m 1 m 2 ) Construct product of m 1 and m 2. Differentiation procedure: (define (deriv exp var) (cond ((constant? exp) (make-constant 0)) ((variable? exp) (if (same-variable? exp var) (make-constant 1) (make-constant 0))) ((sum? exp) (make-sum (deriv (addend exp) var) (deriv (augend exp) var))) ((product? exp) (make-sum (make-product (multiplier exp) (deriv (multiplicand exp) var)) (make-product (deriv (multiplier exp) var) (multiplicand exp)))))) d Recall x = 1, d y = 0, d (U + V ) = d U + d V, d (UV ) = U d V + V d U, and even dx dx dx dx dx dx dx dx d hi dx ho = ho d d hi hi dx hoho dx ho. 1

Simple representations: (define (constant? x) (number? x)) (define (variable? x) (symbol? x)) (define (same-variable? v1 v2) (and (variable? v1) (variable? v2) (eq? v1 v2))) (define (make-constant x) x) (define (make-sum a1 a2) (list + a1 a2)) (define (make-product m1 m2) (list * m1 m2)) (define (sum? x) (if (not (atom? x)) (eq? (car x) +) nil)) (define (addend s) (cadr s)) (define (augend s) (caddr s)) (define (product? x) (if (not (atom? x)) (eq? (car x) *) nil)) (define (multiplier p) (cadr p)) (define (multiplicand p) (caddr p)) Simplification: (define (make-sum a1 a2) (cond ((and (number? a1) (number? a2)) (+ a1 a2)) ((number? a1) (if (= a1 0) a2 (list + a1 a2))) ((number? a2) (if (= a2 0) a1 (list + a1 a2))) (else (list + a1 a2)))) (define (make-product m1 m2) (cond ((and (number? m1) (number? m2)) (* m1 m2)) ((number? m1) (cond ((= m1 0) (make-constant 0)) ((= m1 1) m2) (else (list * m1 m2)))) ((number? m2) (cond ((= m2 0) (make-constant 0)) ((= m2 1) m1) (else (list * m1 m2)))) (else (list * m1 m2)))) Extensions to the system 2

Expanding to handle arbitrary numbers of arguments: (define (augend s) (if (null? (cdddr s)) (caddr s) (append (+) (cddr s)))) (define (multiplicand p) (if (null? (cdddr p)) (caddr p) (append (*) (cddr p)))) Expanding to handle exponentiation: To the deriv procedure, add the following clause, and the subsequent procedures: ((exponential? exp) (make-product (make-product (exponent exp) (make-exponential (base exp) (- (exponent exp) 1))) (deriv (base exp) var))) (define (exponential? exp) (if (not (atom? exp)) (eq? (car exp) **))) (define (base exp) (cadr exp)) (define (exponent exp) (caddr exp)) (define (make-exponential b e) (cond ((= e 0) (make-constant 1)) ((= e 1) b) (else (list ** b e)))) Pattern Matching and Simplification The code on the following pages summarizes the pattern matcher that we will build in this lecture. The basic idea behind this simplification system is to build a set of rules, consisting of a pattern and an evaluation skeleton. Given an expression, we try to match the pattern to the expression, keeping track of the assignment of pattern variables to segments of the expression in a dictionary. If we can perform such a pattern match, then we use the skeleton part of the rule to indicate the procedures that should be evaluated to perform the simplification. 3

An example of the sort of rules we will wish to specify is the following set for algebraic simplification. (define algebra-rules ( ( ((? op) (?c e1) (?c e2)) (: (op e1 e2)) ) ( ((? op) (? e1) (?c e2)) ((: op) (: e2) (: e1)) ) ( (+ 0 (? e)) (: e) ) ( (* 1 (? e)) (: e) ) ( (* 0 (? e)) 0 ) ( (* (?c e1) (* (?c e2) (? e3))) (* (: (* e1 e2)) (: e3)) ) ( (* (? e1) (* (?c e2) (? e3))) (* (: e2) (* (: e1) (: e3))) ) ( (* (* (? e1) (? e2)) (? e3)) (* (: e1) (* (: e2) (: e3))) ) ( (+ (?c e1) (+ (?c e2) (? e3))) (+ (: (+ e1 e2)) (: e3)) ) ( (+ (? e1) (+ (?c e2) (? e3))) (+ (: e2) (+ (: e1) (: e3))) ) ( (+ (+ (? e1) (? e2)) (? e3)) (+ (: e1) (+ (: e2) (: e3))) ) ( (+ (* (?c c) (? a)) (* (?c d) (? a))) (* (: (+ c d)) (: a)) ) ( (* (? c) (+ (? d) (? e))) (+ (* (: c) (: d)) (* (: c) (: e))) ) )) (? x) acts like a variable that can be bound to any expression; (?c x) can similarly be bound to any numeric constant. Then (: x) is the expression that was bound to x, and (: (op x y)) calls the Scheme evaluator (underneath!) with the expressions substituted in for op, x, y. A simple matcher is given below, built on the appropriate data abstractions. This will be used to match the left side of rules against data expressions. (define (match pattern expression dictionary) (cond ((eq? dictionary failed) failed) ((atom? pattern) (if (atom? expression) (if (eq? pattern expression) dictionary failed) failed)) ((arbitrary-constant? pattern) (if (constant? expression) (extend-dictionary pattern expression dictionary) failed)) ((arbitrary-variable? pattern) (if (variable? expression) (extend-dictionary pattern expression dictionary) failed)) ((arbitrary-expression? pattern) (extend-dictionary pattern expression dictionary)) ((atom? expression) failed) (else (match (cdr pattern) (cdr expression) (match (car pattern) (car expression) dictionary))))) 4

Once we have a consistent match, we instantiate the skeleton part of the rule, evaluating when appropriate. (define (instantiate skeleton dictionary) (cond ((atom? skeleton) skeleton) ((skeleton-evaluation? skeleton) (evaluate (evaluation-expression skeleton) dictionary)) (else (cons (instantiate (car skeleton) dictionary) (instantiate (cdr skeleton) dictionary))))) The control of the rule base matcher consists of a series of tightly interwoven recursive loops. The basic idea is that given an expression, we apply the simplification rules in order until we either succeed or run out of rules. Moreover, if the expression to be simplified is compound, this control pattern is applied first to the elementary components of the expression, and then to the resulting simplified whole expression. The procedure simplifier on the next page returns a procedure, based on a set of rules, that can be applied to any expression. (define (simplifier the-rules) (define (simplify-exp exp) (try-rules (if (compound? exp) (simplify-parts exp) exp))) (define (simplify-parts exp) (if (null? exp) () (cons (simplify-exp (car exp)) (simplify-parts (cdr exp))))) (define (try-rules exp) (define (scan rules) (if (null? rules) exp (let ((dictionary (match (pattern (car rules)) exp (make-empty-dictionary)))) (if (eq? dictionary failed) (scan (cdr rules)) (simplify-exp (instantiate (skeleton (car rules)) dictionary)))))) (scan the-rules)) simplify-exp) 5

Having built our simplification system, we now must build the data abstractions on which it rests. The dictionary is represented as a list of pairs, each pair consisting of the variable name and its associated value from the expression. Note that assq is a primitive Scheme procedure which has the behaviour of scanning a list of pairs, testing a key against the first element of each pair. If it finds a pair whose first element is equal to the key, then that pair is returned. (define (make-empty-dictionary) ()) (define (extend-dictionary pat dat dictionary) (let ((vname (variable-name pat))) (let ((v (assq vname dictionary))) (cond ((eq? v #f) (cons (list vname dat) dictionary)) ((equal? (cadr v) dat) dictionary) (else failed))))) (define (lookup var dictionary) (let ((v (assq var dictionary))) (if (eq? v #f) var (cadr v)))) Predicates for types of expressions are straightforward. (define (compound? exp) (pair? exp)) (define (constant? exp) (number? exp)) (define (variable? exp) (atom? exp)) A rule is represented by a list of two parts, a pattern and a skeleton. (define (pattern rule) (car rule)) (define (skeleton rule) (cadr rule)) Within each pattern, explicit objects are represented by themselves, while generic objects are represented by a list, the first element of which identifies the type of generic object, and the second of which identifies the variable name of that object within the pattern. We distinguish three types of generic objects. (define (arbitrary-constant? pat) (if (pair? pat) (eq? (car pat)?c) #f)) (define (arbitrary-expression? pat) (if (pair? pat) (eq? (car pat)?) #f)) (define (arbitrary-variable? pat) (if (pair? pat) (eq? (car pat)?v) #f)) (define (variable-name pat) (cadr pat)) On the skeleton side of the rule, we have two procedures (define (skeleton-evaluation? pat) (if (pair? pat) (eq? (car pat) :) #f)) (define (evaluation-expression evaluation) (cadr evaluation)) The following procedure is included for completeness, but you need not worry about understanding exactly what it does until later in the term. For the purposes of this lecture, you can treat it as an abstraction that evaluates a given form, relative to the assignment of values to variables indicated in the dictionary. 6

(define (evaluate form dictionary) (write (list form dictionary)) (newline) (if (atom? form) (lookup form dictionary) (apply (eval (lookup (car form) dictionary)) (map (lambda (v) (lookup v dictionary)) (cdr form))))) Using the rules we called algebra-rules earlier we can define an algebraic simplification function as: (define algsimp (simplifier algebra-rules)) Exactly the same system can be used to build other symbolic simplifiers. The following rules create a simple symbolic differentiator. (define deriv-rules (( (dd (?c c) (? v)) 0 ) ( (dd (?v v) (? v)) 1 ) ( (dd (?v u) (? v)) 0 ) ( (dd (+ (? x1) (? x2)) (? v)) (+ (dd (: x1) (: v)) (dd (: x2) (: v))) ) ( (dd (* (? x1) (? x2)) (? v)) (+ (* (: x1) (dd (: x2) (: v))) (* (dd (: x1) (: v)) (: x2))) ) ( (dd (** (? x) (?c n)) (? v)) (* (* (: n) (** (: x) (: (- n 1)))) (dd (: x) (: v))) ) )) (define dsimp (simplifier deriv-rules)) In closing, it is worth considering that important aspects of the kind of evaluation characterizing Scheme itself can be captured by such rules. This should not be entirely surprising, since these tables of rules define certain fixed kinds of substitutions, and it is the substitution model that is our current model of Scheme. For example: (define scheme-rules (( (square (?c n)) (: (* n n)) ) ( (fact 0) 1 ) ( (fact (?c n)) (* (: n) (fact (: (- n 1)))) ) ( (fib 0) 0 ) ( (fib 1) 1 ) ( (fib (?c n)) (+ (fib (: (- n 1))) (fib (: (- n 2)))) ) ( ((? op) (?c e1) (?c e2)) (: (op e1 e2)) ) )) (define scheme-evaluator (simplifier scheme-rules)) A good exercise (though by no means trivial) is to work out the substitution model itself via such a set of rules. And for good measure, the computer psychiatrist is another example of symbolic rewriting through these kinds of replacement rules. 7

Epistemology is a big word from philosophy in our case, what it means is how do we represent knowledge? In this handout, we see a procedural epistemology (represent what you know by programs that describe how) and a data epistemology (represent what you know by rules, with a piece of code that inteprets the rules correctly). But correctly is quite a condition consider the following: Suppose we have an algebra rule describing the commutativity of addition: ((+ (? a) (? b)) (+ (: b) (: a))) The rules are applied to simplify an (algebraic) expression until none apply. So (+ x y) is simplified via the commutative law to (+ y x)... which is then simplified back to (+ x y)... and... Rules are also applied from the first to the last, in order. So if we invert the Scheme rules above, so we have instead ( (fact (?c n)) (* (: n) (fact (: (- n 1)))) ) ( (fact 0) 1 ) then (fact 0) gets rewritten to (* 0 (fact -1)) no good. So all of a sudden you realize: the order in which rules get applied affects the result. And the result may involve an infinite loop. So the rules are something which have to get debugged. As a consequence, the rules themselves are no different from code written in your favorite programming language, for better and for worse. The rule interpreter (the matcher, instantiator, etc.) becomes a programming language interpreter. Data and programs end up being the same thing: when you write Scheme code, you think you re writing a program but to the program that is the Scheme interpreter, your code is merely data. 8