home *** CD-ROM | disk | FTP | other *** search
/ Eagles Nest BBS 8 / Eagles_Nest_Mac_Collection_Disc_8.TOAST / Developer Tools⁄Additions / MacScheme20 / Mathlib / multimin.scm < prev    next >
Encoding:
Text File  |  1989-04-27  |  12.9 KB  |  335 lines  |  [TEXT/????]

  1. ;;; $Header: multimin.scm,v 1.4 88/08/26 19:43:49 GMT gjs Exp $
  2. ;;;; MULTIMIN.SCM -- n-dimensional minimization routines
  3.  
  4. (if-mit
  5.  (declare (usual-integrations = + - * /
  6.                  zero? 1+ -1+
  7.                  ;; truncate round floor ceiling
  8.                  sqrt exp log sin cos)))
  9.  
  10. ;;; Nelder-Mead downhill simplex algorithm.
  11.  
  12. ;;; We have a function, f, defined on points in n-space.
  13. ;;; We are looking for a local minimum of f.
  14.  
  15. ;;; The central idea -- We have a simplex of n+1 vertices where f is 
  16. ;;; known.  We want to deform the simplex until it sits on the minimum.
  17.  
  18. ;;; A simplex is represented as a list of entries, each of which is a
  19. ;;; pair consisting of a vertex and the value of f at that vertex.
  20.  
  21. (define simplex-size length)
  22.  
  23. (define simplex-vertex car)
  24. (define simplex-value cdr)
  25. (define simplex-entry cons)
  26.  
  27. ;;; Simplices are stored in sorted order
  28. (define simplex-highest car)
  29. (define simplex-but-highest cdr)
  30. (define simplex-next-highest cadr)
  31. (define (simplex-lowest s) (car (last-pair s)))
  32.  
  33. (define (simplex-add-entry entry s)
  34.   (let ((fv (simplex-value entry)))
  35.     (let loop ((s s))
  36.       (cond ((null? s) (list entry))
  37.             ((> fv (simplex-value (car s))) (cons entry s))
  38.             (else (cons (car s) (loop (cdr s))))))))
  39.  
  40. (define (simplex-adjoin v fv s)
  41.   (simplex-add-entry (simplex-entry v fv) s))
  42.  
  43. (define (simplex-sort s)
  44.   (let lp ((s s) (ans '()))
  45.     (if (null? s)
  46.         ans
  47.         (lp (cdr s) (simplex-add-entry (car s) ans)))))
  48.  
  49. (define simplex-centroid
  50.   (lambda (simplex)
  51.     (scalar*vector (/ 1 (simplex-size simplex))
  52.                    (reduce add-vectors
  53.                            (map simplex-vertex simplex)))))
  54.  
  55. (define    extender    
  56.   (lambda (p1 p2)
  57.     (let ((dp (sub-vectors p2 p1)))
  58.       (lambda (k)
  59.         (add-vectors p1 (scalar*vector k dp))))))
  60.  
  61. (define (make-simplex point step f)
  62.   (simplex-sort
  63.     (map (lambda (vertex) (simplex-entry vertex (f vertex)))
  64.          (cons point
  65.                (map (lambda (unit) (add-vectors point unit))
  66.                 (vector->list 
  67.               (matrix*scalar (identity-matrix (vector-length point))
  68.                              step)))))))
  69.  
  70. (define (stationary? simplex epsilon)
  71.   (close-enuf? (simplex-value (simplex-highest simplex))
  72.                (simplex-value (simplex-lowest simplex))
  73.                epsilon))
  74.  
  75. (define nelder-wallp? false)
  76.  
  77. (define (nelder-mead f start-pt start-step epsilon maxiter)
  78.   (define shrink-coef 0.5)
  79.   (define reflection-coef 2.0)
  80.   (define expansion-coef 3.0)
  81.   (define contraction-coef-1 1.5)
  82.   (define contraction-coef-2 (- 2 contraction-coef-1))
  83.   (define (simplex-shrink point simplex)
  84.     (let ((pv (simplex-vertex point)))
  85.       (simplex-sort
  86.        (map (lambda (sp)
  87.           (if (eq? point sp) 
  88.           sp
  89.           (let ((vertex ((extender pv (simplex-vertex sp)) 
  90.                  shrink-coef)))
  91.             (simplex-entry vertex (f vertex)))))
  92.         simplex))))
  93.   (define (nm-step simplex)
  94.     (let ((g (simplex-highest simplex))
  95.           (h (simplex-next-highest simplex))
  96.           (s (simplex-lowest simplex))
  97.           (s-h (simplex-but-highest simplex)))
  98.       (let* ((vg (simplex-vertex g)) (fg (simplex-value g))
  99.              (fh (simplex-value h)) (fs (simplex-value s))
  100.              (extend (extender vg (simplex-centroid s-h))))
  101.         (let* ((vr (extend reflection-coef))
  102.                (fr (f vr)))                 ;try reflection
  103.           (if (< fr fh)                     ;reflection successful
  104.               (if (< fr fs)                 ;new minimum 
  105.                   (let* ((ve (extend expansion-coef))
  106.                          (fe (f ve)))       ;try expansion
  107.                     (if (< fe fs)           ;expansion successful
  108.                         (simplex-adjoin ve fe s-h)
  109.                         (simplex-adjoin vr fr s-h)))
  110.                   (simplex-adjoin vr fr s-h))
  111.               (let* ((vc (extend (if (< fr fg) 
  112.                                      contraction-coef-1
  113.                                      contraction-coef-2)))
  114.                      (fc (f vc)))           ;try contraction
  115.                 (if (< fc fg)               ;contraction successful
  116.                     (simplex-adjoin vc fc s-h)
  117.                     (simplex-shrink s simplex))))))))
  118.   (define (limit simplex count)
  119.     (if nelder-wallp? (writeln (simplex-lowest simplex)))
  120.     (if (stationary? simplex epsilon)
  121.         (list 'ok (simplex-lowest simplex) count)
  122.         (if (= count maxiter)
  123.             (list 'maxcount (simplex-lowest simplex) count)
  124.             (limit (nm-step simplex) (+ count 1)))))
  125.   (limit (make-simplex start-pt start-step f) 0))
  126.  
  127.  
  128. ;;;(define (stationary? simplex epsilon)
  129. ;;;  (let ((np1 (length simplex)))
  130. ;;;    (let* ((mean (/ (reduce + (map simplex-value simplex)) np1))
  131. ;;;           (variance (/ (reduce + 
  132. ;;;                                (map (lambda (e)
  133. ;;;                                       (square (- (simplex-value e) mean)))
  134. ;;;                                     simplex))
  135. ;;;                        np1)))
  136. ;;;      (< variance epsilon))))
  137.  
  138.  
  139. ;;; Variable Metric Methods:
  140. ;;;    Fletcher-Powell (choice of line search)
  141. ;;;    Broyden-Fletcher-Goldfarb-Shanno (Davidon's line search)
  142.  
  143.  
  144. ;;; The following utility procedure returns a gradient function given a
  145. ;;; differentiable function f of a vector of length n. In general, a gradient
  146. ;;; function accepts an n-vector and returns a vector of derivatives. In this
  147. ;;; case, the derivatives are estimated by richardson-extrapolation of a
  148. ;;; central difference quotient, with the convergence tolerance being a
  149. ;;; specified parameter.
  150.  
  151. (define (generate-gradient-procedure f n tol)
  152.   (lambda (x)
  153.     (generate-vector
  154.       n
  155.       (lambda (i)
  156.         (richardson-limit
  157.           (let ((fi (lambda (t)
  158.                       (f (add-vectors 
  159.                            x 
  160.                            (scalar*vector t (unit-vector n i)))))))
  161.             (lambda (h) (/ (- (fi h) (fi (- h))) 2 h)))
  162.           (max 0.1 (* 0.1 (abs (vector-ref x i)))) ;starting h
  163.           2  ;ord -- see doc for RE.SCM
  164.           2  ;inc
  165.           tol)))))
  166.  
  167.  
  168.  
  169. ;;; The following line-minimization procedure is Davidon's original
  170. ;;; recommendation. It does a bracketing search using gradients, and
  171. ;;; then interpolates the straddled minimum with a cubic.
  172.  
  173. (define (line-min-davidon f g x v est)
  174.   (define (t->x t) (add-vectors x (scalar*vector t v)))
  175.   (define (linef t) (f (t->x t)))
  176.   (define (lineg t) (g (t->x t)))
  177.   (define f0 (linef 0))
  178.   (define g0 (lineg 0))
  179.   (define s0 (/ (- f0 est) -.5 (dot-product g0 v)))
  180.   (let loop ((t (if (and (positive? s0) (< s0 1)) s0 1))
  181.              (iter 0))
  182.     (if (> iter 100)
  183.         (list 'no-min)
  184.         (let ((ft (linef t))
  185.               (gt (lineg t)))
  186.           (if (or (>= ft f0)
  187.                   (>= (dot-product v gt) 0))
  188.               (let* ((vg0 (dot-product v g0))
  189.                      (vgt (dot-product v gt))
  190.                      (z (+ (* 3 (- f0 ft) (/ 1 t)) vg0 vgt))
  191.                      (w (sqrt (- (* z z) (* vg0 vgt))))
  192.                      (tstar (* t (- 1 (/ (+ vgt w (- z)) 
  193.                                          (+ vgt (- vg0) (* 2 w))))))
  194.                      (fstar (linef tstar)))
  195.                  (if (< fstar f0)
  196.                      (list 'ok (t->x tstar) fstar)
  197.                      (loop tstar (+ iter 1))))
  198.               (loop (* t 2) (+ iter 1)))))))
  199.   
  200.   
  201.   
  202. ;;; The following line-minimization procedure is based on Brent's
  203. ;;; algorithm.
  204.  
  205. (define (line-min-brent f g x v est)
  206.   (define (t->x t) (add-vectors x (scalar*vector t v)))
  207.   (define (linef t) (f (t->x t)))
  208.   (define (lineg t) (g (t->x t)))
  209.   (define f0 (linef 0))
  210.   (define g0 (lineg 0))
  211.   (define s0 (/ (- f0 est) -.5 (dot-product g0 v)))
  212.   (let loop ((t (if (and (positive? s0) (< s0 1)) s0 1))
  213.          (iter 0))
  214.     (if (> iter 100)
  215.     (list 'no-min)
  216.     (let ((ft (linef t))
  217.           (gt (lineg t)))
  218.       (if (or (>= ft f0)
  219.           (>= (dot-product v gt) 0))
  220.           (let* ((result (brent-min linef 0 t *sqrt-machine-epsilon*))
  221.              (tstar (car result))
  222.              (fstar (cadr result)))
  223.         (list 'ok (t->x tstar) fstar))
  224.           (loop (* t 2) (+ iter 1)))))))
  225.  
  226.  
  227. ;;; In the following implementation of the Davidon-Fletcher-Powell
  228. ;;;  algorithm, f is a function of a single vector argument that returns
  229. ;;;  a real value to be minimized, g is the vector-valued gradient and
  230. ;;;  x is a (vector) starting point, and est is an estimate of the minimum
  231. ;;;  function value. If g is '(), then a numerical approximation is 
  232. ;;;  substituted using GENERATE-GRADIENT-PROCEDURE. ftol is the convergence 
  233. ;;;  criterion: the search is stopped when the relative change in f falls 
  234. ;;;  below ftol.
  235.  
  236. (define fletcher-powell-wallp? false)
  237.  
  238. (define (fletcher-powell line-search f g x est ftol maxiter)
  239.   (let ((n (vector-length x)))
  240.     (if (null? g) (set! g (generate-gradient-procedure 
  241.                             f n (* 1000 *machine-epsilon*))))
  242.     (let loop ((H (identity-matrix n))
  243.                (x x)
  244.                (fx (f x))
  245.                (gx (g x))
  246.                (count 0))
  247.       (if fletcher-powell-wallp? (print (list x fx gx)))
  248.       (let ((v (matrix*vector H (scalar*vector -1 gx))))
  249.         (if (positive? (dot-product v gx))
  250.           (begin 
  251.             (if fletcher-powell-wallp? 
  252.                (display (list "H reset to Identity at iteration" count)))
  253.             (loop (identity-matrix n) x fx gx count))
  254.           (let ((r (line-search f g x v est)))
  255.             (if (eq? (car r) 'no-min)
  256.               (list 'no-min (cons x fx) count)
  257.               (let ((newx (cadr r))
  258.                     (newfx (caddr r)))
  259.                 (if (close-enuf? newfx fx ftol) ;convergence criterion
  260.                   (list 'ok (cons newx newfx) count)
  261.                   (if (= count maxiter)
  262.                     (list 'maxcount (cons newx newfx) count)
  263.                     (let* ((newgx (g newx))
  264.                            (dx (sub-vectors newx x))
  265.                            (dg (sub-vectors newgx gx))
  266.                            (Hdg (matrix*vector H dg))
  267.                            (A (matrix*scalar (outer-product dx dx)
  268.                                              (/ 1 (dot-product dx dg))))
  269.                            (B (matrix*scalar (outer-product Hdg Hdg)
  270.                                              (/ -1 (dot-product dg Hdg))))
  271.                            (newH (add-matrices H A B)))
  272.                       (loop newH newx newfx newgx (+ count 1)))))))))))))
  273.  
  274.  
  275. ;;; The following procedures, DFP and DFP-BRENT, call directly upon
  276. ;;; FLETCHER-POWELL. The first uses Davidon's line search which is
  277. ;;; efficient, and would be the normal choice. The second uses Brent's
  278. ;;; line search, which is less efficient but more reliable.
  279.  
  280. (define (dfp f g x est ftol maxiter)
  281.   (fletcher-powell line-min-davidon f g x est ftol maxiter))
  282.  
  283. (define (dfp-brent f g x est ftol maxiter)
  284.   (fletcher-powell line-min-brent f g x est ftol maxiter))
  285.  
  286. ;;; The following is a variation on DFP, due (independently, we are told)
  287. ;;; to Broyden, Fletcher, Goldfarb, and Shanno. It differs in the formula
  288. ;;; used to update H, and is said to be more immune than DFP to imprecise
  289. ;;; line-search. Consequently, it is offered with Davidon's line search
  290. ;;; wired in.
  291.  
  292. (define bfgs-wallp? false)
  293.  
  294. (define (bfgs f g x est ftol maxiter)
  295.   (let ((n (vector-length x)))
  296.     (if (null? g) (set! g (generate-gradient-procedure 
  297.                             f n (* 1000 *machine-epsilon*))))
  298.     (let loop ((H (identity-matrix n))
  299.                (x x)
  300.                (fx (f x))
  301.                (gx (g x))
  302.                (count 0))
  303.       (if bfgs-wallp? (print (list x fx gx)))
  304.       (let ((v (matrix*vector H (scalar*vector -1 gx))))
  305.         (if (positive? (dot-product v gx))
  306.           (begin 
  307.             (if bfgs-wallp? 
  308.                (display (list "H reset to Identity at iteration" count)))
  309.             (loop (identity-matrix n) x fx gx count))
  310.           (let ((r (line-min-davidon f g x v est)))
  311.             (if (eq? (car r) 'no-min)
  312.               (list 'no-min (cons x fx) count)
  313.               (let ((newx (cadr r))
  314.                     (newfx (caddr r)))
  315.                 (if (close-enuf? newfx fx ftol) ;convergence criterion
  316.                   (list 'ok (cons newx newfx) count)
  317.                   (if (= count maxiter)
  318.                     (list 'maxcount (cons newx newfx) count)
  319.                     (let* ((newgx (g newx))
  320.                            (dx (sub-vectors newx x))
  321.                            (dg (sub-vectors newgx gx))
  322.                            (Hdg (matrix*vector H dg))
  323.                            (dxdg (dot-product dx dg))
  324.                            (dgHdg (dot-product dg Hdg))
  325.                            (u (sub-vectors (scalar*vector (/ 1 dxdg) dx)
  326.                                            (scalar*vector (/ 1 dgHdg) Hdg)))
  327.                            (A (matrix*scalar (outer-product dx dx)
  328.                                              (/ 1 dxdg)))
  329.                            (B (matrix*scalar (outer-product Hdg Hdg)
  330.                                              (/ -1 dgHdg)))
  331.                            (C (matrix*scalar (outer-product u u) dgHdg))
  332.                            (newH (add-matrices H A B C)))
  333.                         (loop newH newx newfx newgx (+ count 1)))))))))))))
  334.  
  335.