In article <43jv52$
...@mira.sara.nl> pin
...@ampere.phys.uva.nl () writes:
> I wrote a lisp interpreter, and I'm now finding that speed is
> becoming important for me. Could any one supply me with
> info on what order of magnitude speed up I can expect
> (roughly) when I add in a byte-code compiler? (I do want to
> keep it portable...)
This is a recent post to the genetic programming mailing list. It briefly
describes Marc Feeley's approach of compiling with closures.
;;; Here is some Common Lisp code that outlines some evaluation strategies
;;; that can be useful in genetic programming. The approach used here
;;; basically follows the approach in Koza's first book.
;;; For example, say we have some data:
(setq data '(1.0 2.0 3.0))
;;; and we'd like to evaluate the expression, EXP, which was generated by a
;;; genetic program:
(setq exp '(+ (* 3.0 (square x)) 2.0))
;;; Here we use Lisp s-expressions, but the follow ideas work for other
;;; data structures as well.
;;; How the expression is evaluated is a major performance issue in genetic
;;; programming. See for example, ftp: openmap.bbn.com: pub/kanderson/
;;; faster94/faster94/postscript/profile.ps
;;; Here are 4 approaches to EVAL. The fourth one, gp-eval-3, uses the
;;; closure compiler idea of Marc Feeley, which is the main point of this
;;; message. This compiler is very fast and can do some very useful
;;; optimizations. I have not used this in a genetic programming
;;; application, i thought the idea was worth sharing.
;;; While the examples are in Lisp, the ideas can be ported to other
;;; languages, perhaps with a bit more work.
(defun square (x) (* x x))
(defun gp-eval-0 (data exp)
;; Use Common Lisp's EVAL.
;; Problem: EVAL is too general.
(mapcar
#'(lambda (x)
(declare (special x))
(eval exp))
data))
(defun gp-eval-1 (data exp)
;; Use COMPILE and FUNCALL instead of EVAL.
;; Problem: Combined time of COMPILE + N*FUNCALL can be larger than N*EVAL.
(let ((f (compile 'nil `(lambda (x) ,exp))))
(mapcar f data)))
(defun gp-eval-error (exp) (error "Can't handle ~a" exp))
(defun gp-eval-2 (data exp)
;; Use specialized version of EVAL
;; Problem: still must recursively EVAL EXP.
;; Could do a data parallel version.
;; Could unroll the recursion.
;; Could use a variable stack rather than recursion.
(labels
((eval (x exp)
(cond ((eq exp 'x) x)
((consp exp)
(case (car exp)
(+ (+ (eval x (cadr exp)) (eval x (caddr exp))))
(* (* (eval x (cadr exp)) (eval x (caddr exp))))
(square (square (eval x (cadr exp))))
(t (gp-eval-error exp))))
(t exp)))) ; Constant.
(mapcar #'(lambda (x) (eval x exp)) data)))
(defun gp-eval-3 (data exp)
;; Use closure compiler.
;; Could perform optimizations by adding more cases, like (+ x <constant>).
;; Memoizing would be very useful in a gentic program.
;; Could evolve compiled code directly.
;; Can be used in languages that do not have closures.
(macrolet
((code (form) `#'(lambda (x) ,form))
(call (code) `(funcall ,code x)))
(labels
((gen (exp)
(cond ((eq exp 'x) (code x))
((consp exp)
(case (car exp)
(+ (let ((a (gen (cadr exp)))
(b (gen (caddr exp))))
(code (+ (call a) (call b)))))
(* (let ((a (gen (cadr exp)))
(b (gen (caddr exp))))
(code (* (call a) (call b)))))
(square (let ((a (gen (cadr exp))))
(code (square (call a)))))
(t (gp-eval-error exp))))
(t (code exp)))))
(let ((f (gen exp)))
(mapcar #'(lambda (x) (call f)) data)))))
--
Ken Anderson
Internet: kander...@bbn.com
BBN ST Work Phone: 617-873-3160
10 Moulton St. Home Phone: 617-643-0157
Mail Stop 6/4a FAX: 617-873-2794
Cambridge MA 02138
USA