summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ps04_combinators_amb/analyze-amb.scm17
-rw-r--r--ps04_combinators_amb/bnewbold_ps04.txt174
-rw-r--r--ps04_combinators_amb/bnewbold_ps04_work.scm231
-rw-r--r--ps04_combinators_amb/load-amb.scm7
-rw-r--r--ps04_combinators_amb/load-analyze.scm4
-rw-r--r--ps04_combinators_amb/multiple-dwelling_edit.scm32
-rw-r--r--ps04_combinators_amb/repl-amb.scm6
7 files changed, 462 insertions, 9 deletions
diff --git a/ps04_combinators_amb/analyze-amb.scm b/ps04_combinators_amb/analyze-amb.scm
index 5d5ad56..cc98c12 100644
--- a/ps04_combinators_amb/analyze-amb.scm
+++ b/ps04_combinators_amb/analyze-amb.scm
@@ -2,6 +2,13 @@
;;; Execution procedures take environment
;;; and two continuations: SUCCEED and FAIL
+(define *amb-count* 0)
+(define (show-amb-count)
+ (display "Number of alts considered: ")
+ (display *amb-count*)
+ (newline)
+ (set! *amb-count* 0))
+
(define (ambeval exp env succeed fail)
((analyze exp) env succeed fail))
@@ -187,10 +194,12 @@
(let loop ((alts aprocs))
(if (null? alts)
(fail)
- ((car alts) env
- succeed
- (lambda ()
- (loop (cdr alts)))))))))
+ (begin
+ (set! *amb-count* (+ 1 *amb-count*))
+ ((car alts) env
+ succeed
+ (lambda ()
+ (loop (cdr alts))))))))))
(defhandler analyze analyze-amb amb?)
diff --git a/ps04_combinators_amb/bnewbold_ps04.txt b/ps04_combinators_amb/bnewbold_ps04.txt
index 0203e57..58d49b1 100644
--- a/ps04_combinators_amb/bnewbold_ps04.txt
+++ b/ps04_combinators_amb/bnewbold_ps04.txt
@@ -4,15 +4,187 @@
Problem 4.1: Warmup
---------------------
+The way I interpreted this question, all the parameters are passed in one list,
+as opposed to a finite list of specified parameters plus an arbitrary length
+list containing all the "left over" parameters.
+
Problem 4.2: Infix Notation
-----------------------------
+I attacked this problem with the natural language pattern matching technique
+described in SICP. First I wrote a crude register-machine-style parser which
+turns the infix string into a list which is easier to parse and match over.
+Each element in the list is tagged with it's type (eg, number, variable,
+open-parenthesis, etc). Then I identified the following types of expressions:
+
+ number: [number]
+ variable: [variable]
+ binary: [expression] [oper] [expression]
+ chunk: [open-paren] [expression] [close-paren]
+ function: [variable] [open-paren] [expression] [close-paren]
+
+There's potential for an infinite loop when trying to match an expression
+as a binary expression starting with an expression starting with a binary
+expression [etc etc], so I defined "simple-expressions" as any of the above
+types minus binary, and redefined binary as:
+
+ binary: [simple-expression] [oper] [expression]
+
+I'm pretty sure this keeps the system general.
+
+Then I do amb-style pattern matching with requires, and finally "lispify"
+the resulting parse tree into an s-expression and evaluate it.
+
+To do the final evaluation of the parsed code I added this line to
+load-amb.scm:
+
+(define (eval-in-amb exp)
+ (eval exp generic-evaluation-environment))
+
+This doesn't really work the way I want, but the-global-environment apparently
+isn't a real environment (?!?!) and I can't get the usual
+nearest-repl/environment. Variables defined in the
+generic-evaluation-environment are substituted properly into the final
+evaluation. Eg:
+
+ ;;; Amb-Eval input:
+ (define y 10)
+
+ ;;; Starting a new problem
+ ;;; Amb-Eval value:
+ Number of alts considered: 0
+ y
+
+ ;;; Amb-Eval input:
+ (infix "y")
+
+ ;;; Starting a new problem
+ ;Unbound variable: y
+
+But then,
+
+ 1 ]=> (define x 5)
+ ;Value: x
+
+ 1 ]=> (go)
+
+ ;;; Amb-Eval input:
+ (infix "x")
+ ;;; Starting a new problem
+ ;;; Amb-Eval value:
+ Number of alts considered: 4
+ 5
-Problem 4.3: Programming with AMB
+There are one or two other missing pieces: all operators are binary without the
+appropriate precedence, decimal numbers aren't recognized, variables have to
+be lowercase, negative numbers don't work (use, eg, 0-45 instead), and operators
+are just any string of characters made up of "*+/-^" passed straight through,
+so exponentiation doesn't work.
+
+[see code in bnewbold_ps04_work.scm]
+
+Problem 4.38
+-----------------------------------
+This was only a one line change in the code, remove the line:
+
+ (require (not (= (abs (- fletcher smith)) 1)))
+
+By trying it in the evaluator, I found 5 possible solutions:
+
+ ((baker 1) (cooper 2) (fletcher 4) (miller 3) (smith 5))
+ ((baker 1) (cooper 2) (fletcher 4) (miller 5) (smith 3))
+ ((baker 1) (cooper 4) (fletcher 2) (miller 5) (smith 3))
+ ((baker 3) (cooper 2) (fletcher 4) (miller 5) (smith 1))
+ ((baker 3) (cooper 4) (fletcher 2) (miller 5) (smith 1))
+
+Problem 4.39
+-----------------------------------
+The order matters in that it can change the order that solutions are found,
+and definately changes the speed with which they are found. The actual set of
+solutions does not change; all solutions will still meet the requirements.
+
+The given order of the requirements actually does a reasonable job optimizing
+for the speed of the search. Putting the most restrictive requirements first
+will help reduce the number of checks and backtraces performed, so I would put
+the (require (> miller cooper)) first.
+
+Problem 4.40
-----------------------------------
+There are 5^5=3125 assignments before the distinct requirement and 5!=120 after.
+Here's my fast version:
+(define (multiple-dwelling-fast)
+ (let ((fletcher (amb 1 2 3 4 5)))
+ (require (not (= fletcher 5)))
+ (require (not (= fletcher 1)))
+ (let ((cooper (amb 1 2 3 4 5)))
+ (require (not (= cooper 1)))
+ (require (not (= (abs (- fletcher cooper)) 1)))
+ (let ((miller (amb 1 2 3 4 5)))
+ (require (> miller cooper))
+ (let ((smith (amb 1 2 3 4 5)))
+ (require (not (= (abs (- smith fletcher)) 1)))
+ (let ((baker (amb 1 2 3 4 5)))
+ (require (not (= baker 5)))
+ (require
+ (distinct (list baker cooper fletcher miller smith)))
+ (list (list 'baker baker)
+ (list 'cooper cooper)
+ (list 'fletcher fletcher)
+ (list 'miller miller)
+ (list 'smith smith))))))))
+
+Of coure a big help would be simply removing the impossible floors from the amb
+statements for individual people; eg because Cooper can't live on the first
+floor, just remove 1 from that amb statement.
Problem 4.4: Profiling AMB
----------------------------
+My version ("multiple-dwelling-fast") makes 210 alternative attempts, while the
+original makes 1840 attempts.
+
+The changes I made were to analyze-amb.scm:
+
+(define *amb-count* 0)
+(define (show-amb-count)
+ (display "Number of alts considered: ")
+ (display *amb-count*)
+ (newline)
+ (set! *amb-count* 0))
+
+and repl-amb.scm:
+
+(define (driver-loop)
+ (define (internal-loop try-again)
+ (let ((input
+ (prompt-for-command-expression input-prompt)))
+ (if (eq? input 'try-again)
+ (try-again)
+ (begin
+ (newline)
+ (display ";;; Starting a new problem ")
+ (evaluator
+ input
+ (lambda (val next-alternative)
+ (display output-prompt)
+ (show-amb-count) ;;;;;;;;; THIS LINE ADDED
+ (pp val)
+ (internal-loop next-alternative))
+ (lambda ()
+ (display ";;; There are no more values of ")
+ (pp input)
+ (driver-loop)))))))
+ (internal-loop
+ (lambda ()
+ (display ";;; There is no current problem")
+ (driver-loop))))
+
+#| Example:
+eval> (multiple-dwelling)
+;;; Starting a new problem
+;;; Amb-Eval value:
+Number of alts considered: 1840
+((baker 3) (cooper 2) (fletcher 4) (miller 5) (smith 1))
+|#
diff --git a/ps04_combinators_amb/bnewbold_ps04_work.scm b/ps04_combinators_amb/bnewbold_ps04_work.scm
index e69de29..5bcaf99 100644
--- a/ps04_combinators_amb/bnewbold_ps04_work.scm
+++ b/ps04_combinators_amb/bnewbold_ps04_work.scm
@@ -0,0 +1,231 @@
+;;; 6.945 Problem Set #4 Source Code
+;;; 03/04/2009
+;;; Bryan Newbold <bnewbold@mit.edu>
+
+; Note: this file is usually loaded from the load-*.scm files into
+; the-generic-evaluation-environment
+
+;---------------------------
+; Problem 4.1
+
+#| ; This conflicts with the infix code below, so leave it commented in
+ ; when testing that code.
+
+(defhandler execute-application
+ (lambda (proc args)
+ ((procedure-body proc)
+ (if (list? (procedure-parameters proc))
+ (extend-environment
+ (procedure-parameters proc)
+ args
+ (procedure-environment proc))
+ (extend-environment
+ (list (procedure-parameters proc))
+ (list args)
+ (procedure-environment proc)))))
+ compound-procedure?)
+|#
+#| Testing:
+
+eval> (define (ss . x) (map square x))
+ok
+eval> (ss 1 2 3)
+(1 4 9)
+
+; and the regular syntax still works:
+
+eval> (define (s2 x y) (list (square x) (square y)))
+ok
+eval> (s2 1 2 3 4 5)
+;Too many arguments supplied (x y) (1 2 3 4 5)
+eval> (s2 1 2)
+(1 4)
+|#
+
+
+;---------------------------
+; Problem 4.2
+
+; first we gotta listify the infix string or life will suck
+(define (infix-operator? x)
+ (member x (string->list "+-*^/")))
+(define (infix-open-paren? x)
+ (member x (string->list "(")))
+(define (infix-close-paren? x)
+ (member x (string->list ")")))
+(define (infix-var? x)
+ (member x (string->list "abcdefghijklmnopqrstuvwxyz")))
+(define (infix-number? x)
+ (member x (string->list "0123456789")))
+(define (infix-same-type? a b)
+ (cond ((infix-operator? a) (infix-operator? b))
+ ((infix-open-paren? a) (infix-open-paren? b))
+ ((infix-close-paren? a) (infix-close-paren? b))
+ ((infix-number? a) (infix-number? b))
+ ((infix-var? a) (infix-var? b))
+ (else (error "Not a valid infix char type: " a))))
+(define (infix-tag-type x)
+ (let ((tag (cond ((infix-operator? (car x)) 'oper)
+ ((infix-open-paren? (car x)) 'open-paren)
+ ((infix-close-paren? (car x)) 'close-paren)
+ ((infix-var? (car x)) 'variable)
+ ((infix-number? (car x)) 'number)
+ (else (error "Something wrong, not a type: " x)))))
+ (list tag (list->string (reverse x)))))
+
+(define (listify in)
+ (define out '())
+ (define prog '())
+ (define (work chunk)
+ (cond ((null? chunk)
+ (cons (infix-tag-type prog) out))
+ ((equal? (car chunk) #\space)
+ (work (cdr chunk)))
+ ((null? prog)
+ (begin
+ (set! prog (cons (car chunk) prog))
+ (work (cdr chunk))))
+ ((and (infix-same-type? (car prog) (car chunk))
+ (not (or (infix-open-paren? (car prog))
+ (infix-close-paren? (car prog)))))
+ (begin
+ (set! prog (cons (car chunk) prog))
+ (work (cdr chunk))))
+ (else
+ (begin
+ (set! out (cons (infix-tag-type prog) out))
+ (set! prog (list (car chunk)))
+ (work (cdr chunk))))))
+ (reverse (work (string->list in))))
+
+#| Test:
+(listify "4+34^4-(a*a+b^2)")
+;Value: ((number "4") (oper "+") (number "34") (oper "^") (number "4") (oper "-") (open-paren "(") (var "a") (oper "*") (var "a") (oper "+") (var "b") (oper "^") (number "2") (close-paren ")"))
+
+(listify "4+34^4 - ( a*a + b^2)")
+;Value: ((number "4") (oper "+") (number "34") (oper "^") (number "4") (oper "-") (open-paren "(") (var "a") (oper "*") (var "a") (oper "+") (var "b") (oper "^") (number "2") (close-paren ")"))
+|#
+
+; alright, now we can do fun NLP mojo
+
+
+#| These definitions should be pasted into an amb-evaluator:
+
+(define (require p)
+ (if (not p) (amb)))
+
+(define *unparsed* '())
+
+(define (parse-type t)
+ (require (not (null? *unparsed*)))
+ (require (equal? (caar *unparsed*) t))
+ (let ((found-type (car *unparsed*)))
+ (set! *unparsed* (cdr *unparsed*))
+ found-type))
+
+(define (parse-binary)
+ (list 'binary
+ (parse-simple-expression)
+ (parse-type 'oper)
+ (parse-expression)))
+
+(define (parse-chunk)
+ (list 'chunk
+ (parse-type 'open-paren)
+ (parse-expression)
+ (parse-type 'close-paren)))
+
+(define (parse-function)
+ (list 'function
+ (parse-type 'variable)
+ (parse-chunk)))
+
+(define (parse-simple-expression)
+ (amb (parse-type 'number)
+ (parse-type 'variable)
+ (parse-chunk)
+ (parse-function)))
+
+(define (parse-expression)
+ (amb (parse-type 'number)
+ (parse-type 'variable)
+ (parse-binary)
+ (parse-chunk)
+ (parse-function)))
+
+(define (parse-infix in)
+ (set! *unparsed* (listify in))
+ (let ((sent (parse-expression)))
+ (require (null? *unparsed*))
+ sent))
+
+#| Test:
+;;; Amb-Eval input:
+(parse-infix "sqrt(5+square(4*4))")
+
+;;; Starting a new problem
+;;; Amb-Eval value:
+Number of alts considered: 99
+(function
+ (variable "sqrt")
+ (chunk
+ (open-paren "(")
+ (binary
+ (number "5")
+ (oper "+")
+ (function
+ (variable "square")
+ (chunk (open-paren "(")
+ (binary (number "4") (oper "*") (number "4"))
+ (close-paren ")"))))
+ (close-paren ")")))
+
+;;; Amb-Eval input:
+(parse-infix "1+2+4+5")
+
+;;; Starting a new problem
+;;; Amb-Eval value:
+Number of alts considered: 13
+(binary
+ (number "1")
+ (oper "+")
+ (binary (number "2")
+ (oper "+")
+ (binary (number "4") (oper "+") (number "5"))))
+
+|#
+
+(define (lispify parsed)
+ (cond ((eq? (car parsed) 'function)
+ (list (lispify (car (cdr parsed)))
+ (lispify (car (cdr (cdr parsed))))))
+ ((eq? (car parsed) 'variable)
+ (string->symbol (car (cdr parsed))))
+ ((eq? (car parsed) 'number)
+ (string->number (car (cdr parsed))))
+ ((eq? (car parsed) 'binary)
+ (list (lispify (car (cdr (cdr parsed))))
+ (lispify (car (cdr parsed)))
+ (lispify (car (cdr (cdr (cdr parsed)))))))
+ ((eq? (car parsed) 'chunk)
+ (lispify (car (cdr (cdr parsed)))))
+ ((eq? (car parsed) 'oper)
+ (string->symbol (car (cdr parsed))))
+ (else (error "Unhandled type: " (car parsed)))))
+
+; note, this requres eval-in-amb to be defined in the top level
+(define (infix in)
+ (eval-in-amb (lispify (parse-infix in))))
+
+#|
+; x needs to be defined in the top level; here it's 5
+
+;;; Amb-Eval input:
+(infix "sqrt(4+3/x*square(56 - 83))")
+
+;;; Starting a new problem
+;;; Amb-Eval value:
+Number of alts considered: 146
+2.0002057507335316
+
+|#
diff --git a/ps04_combinators_amb/load-amb.scm b/ps04_combinators_amb/load-amb.scm
index 6f3d1a8..a2ec775 100644
--- a/ps04_combinators_amb/load-amb.scm
+++ b/ps04_combinators_amb/load-amb.scm
@@ -7,8 +7,11 @@
(define generic-evaluation-environment
(extend-top-level-environment user-initial-environment))
+(define (eval-in-amb exp)
+ (eval exp generic-evaluation-environment))
+
(load "analyze-amb" generic-evaluation-environment)
+(load "bnewbold_ps04_work" generic-evaluation-environment)
(load "repl-amb" generic-evaluation-environment)
-
-(ge generic-evaluation-environment) \ No newline at end of file
+(ge generic-evaluation-environment)
diff --git a/ps04_combinators_amb/load-analyze.scm b/ps04_combinators_amb/load-analyze.scm
index 02e447e..1d274ae 100644
--- a/ps04_combinators_amb/load-analyze.scm
+++ b/ps04_combinators_amb/load-analyze.scm
@@ -3,11 +3,11 @@
(load "syntax" user-initial-environment)
(load "rtdata" user-initial-environment)
-
(define generic-evaluation-environment
(extend-top-level-environment user-initial-environment))
(load "analyze" generic-evaluation-environment)
+(load "bnewbold_ps04_work" generic-evaluation-environment)
(load "repl" generic-evaluation-environment)
-(ge generic-evaluation-environment) \ No newline at end of file
+(ge generic-evaluation-environment)
diff --git a/ps04_combinators_amb/multiple-dwelling_edit.scm b/ps04_combinators_amb/multiple-dwelling_edit.scm
new file mode 100644
index 0000000..e6ee53d
--- /dev/null
+++ b/ps04_combinators_amb/multiple-dwelling_edit.scm
@@ -0,0 +1,32 @@
+
+(define (require p)
+ (if (not p) (amb)))
+
+(define (distinct l)
+ (cond ((null? l) true)
+ ((null? (cdr l)) true)
+ ((member (car l) (cdr l)) false)
+ (else (distinct (cdr l)))))
+
+
+(define (multiple-dwelling-fast)
+ (let ((fletcher (amb 1 2 3 4 5)))
+ (require (not (= fletcher 5)))
+ (require (not (= fletcher 1)))
+ (let ((cooper (amb 1 2 3 4 5)))
+ (require (not (= cooper 1)))
+ (require (not (= (abs (- fletcher cooper)) 1)))
+ (let ((miller (amb 1 2 3 4 5)))
+ (require (> miller cooper))
+ (let ((smith (amb 1 2 3 4 5)))
+ (require (not (= (abs (- smith fletcher)) 1)))
+ (let ((baker (amb 1 2 3 4 5)))
+ (require (not (= baker 5)))
+ (require
+ (distinct (list baker cooper fletcher miller smith)))
+ (list (list 'baker baker)
+ (list 'cooper cooper)
+ (list 'fletcher fletcher)
+ (list 'miller miller)
+ (list 'smith smith))))))))
+
diff --git a/ps04_combinators_amb/repl-amb.scm b/ps04_combinators_amb/repl-amb.scm
index c7b6ccb..90311b0 100644
--- a/ps04_combinators_amb/repl-amb.scm
+++ b/ps04_combinators_amb/repl-amb.scm
@@ -66,6 +66,7 @@
input
(lambda (val next-alternative)
(display output-prompt)
+ (show-amb-count)
(pp val)
(internal-loop next-alternative))
(lambda ()
@@ -78,3 +79,8 @@
(driver-loop))))
(define go driver-loop)
+
+
+
+
+