Updated testsuite with an expected GCL error in to_poly_share
[maxima.git] / share / cobyla / cobyla-interface.lisp
blob801e1e5d01b467dd8d1410fb1fd598470a7ffa76
1 ;;; -*- Mode: lisp -*-
3 ;;; Simple Maxima interface to COBYLA, Constrained Optimization BY
4 ;;; Linear Approximations.
6 (in-package #:maxima)
8 (defvar *debug-cobyla* nil
9 "Non-Nil to enable some debugging prints in the coblya interface")
11 ;; Variable that will hold the function that calculates the function
12 ;; value and the constraints.
13 (defvar *calcfc*)
15 ;; COBYLA always calls CALCFC to compute the function value and the
16 ;; constraint equations. But we want to be able to specify different
17 ;; versions. So, COBYLA calls CALCFC, which then calls *CALCFC* to
18 ;; do the real computation.
19 (defun cobyla::calcfc (n m x f con)
20 (declare (ignore f))
21 (funcall maxima::*calcfc* n m x con))
23 (defmfun $fmin_cobyla
24 (f vars init-x
25 &key constraints (rhobeg 1d0) (rhoend 1d-6) ( iprint 0) (maxfun 1000))
26 "COBYLA (Constrained Optimization BY Linear Approximation).
28 This is a maxima interface to the routine COBYLA. Interface
29 Copyright Raymond Toy 2010 Interface released under the terms of the
30 GNU General Public License.
32 The COBYLA Fortran routines are included with permission from the
33 author Michael J. D. Powell, 2010/10/08. The code was obtained from
34 http://plato.asu.edu/sub/nlores.html#general.
36 fmin_cobyla(f, vars, init_x, [args])
38 f Real function to be minimized
39 vars List of variables over which to minimize
40 init_x Initial guess. Do NOT set to all zeroes.
42 The optional arguments are all keyword arguments of the form key =
43 value:
45 constraints List of expressions for the constraints on the variables.
46 Each expression is assumed to be greater than or equal
47 to zero. Constraints must be of the form f >= g, f <=
48 g, or f = g.
49 rhobeg Initial value of the internal RHO variable which controls
50 the size of simplex. (Defaults to 1.)
51 rhoend The desired final value rho parameter. It is approximately
52 the accuracy in the variables. (Defaults to 1d-6.)
53 iprint Verbose output level. (Defaults to 0.)
54 0 - No output
55 1 - Summary at the end of the calculation
56 2 - Each new value of RHO and SIGMA is printed, including
57 the vector of variables, some function information when
58 RHO is reduced.
59 3 - Like 2, but information is printed when F(X) is computed.
60 maxfun The maximum number of function evaluations. (Defaults to
61 1000).
63 The parameter SIGMA is an internal penalty parameter, it being
64 assumed that a change to X is an improvement if it reduces the merit
65 function
67 F(X)+SIGMA*MAX(0.0,-C1(X),-C2(X),...,-CM(X))
69 where C1, C2 are the constraint functions. When printed the
70 parameter MAXCV is the MAX term above, which stands for MAXimum
71 Constraint Violation.
73 On return, a vector of four elements is given:
75 1: The value of the variables giving the minimum
76 2: The minimized function value
77 3: The number of function evaluations.
78 4: Success code:
79 0 - success
80 1 - maxfun limit reached
81 2 - rounding issues
82 -1 - maxcv exceeds rhoend probably indicating constraints not
83 satisfied.
85 You can find some examples in share/cobyla/ex.
87 An example of minimizing x1*x2 with 1-x1^2-x2^2 >= 0:
89 load(fmin_cobyla);
90 fmin_cobyla(x1*x2, [x1, x2], [1,1], constraints = [1-x1^2-x2^2 >= 0], iprint=1);
92 => [[x1 = 0.707107555323284, x2 = - 0.7071060070503778],
93 - 0.4999999999998015, 64, 0]
95 The theoretical solution is x1 = 1/sqrt(2), x2 = -1/sqrt(2).
97 (unless (listp vars)
98 (merror "~M: vars must be a list of variables. Got: ~M"
99 %%pretty-fname vars))
100 (unless (listp init-x)
101 (merror "~M: Initial values must be a list of values. Got: ~M"
102 %%pretty-fname init-x))
104 (unless (= (length (cdr vars))
105 (length (cdr init-x)))
106 (merror
107 "~M: Number of initial values (~M) does not match the number of variables ~M~%"
108 %%pretty-fname
109 (length (cdr init-x))
110 (length (cdr vars))))
112 (unless (and (integerp iprint)
113 (<= 0 iprint 3))
114 (merror
115 "~M: iprint must be an integer between 0 and 3, inclusive, not: ~M~%"
116 %%pretty-fname iprint))
118 (unless (and (integerp maxfun) (plusp maxfun))
119 (merror
120 "~M: maxfun must be a positive integer, not: ~M~%"
121 %%pretty-fname maxfun))
123 ;; Go through constraints and convert f >= g to f - g, f <= g to g -
124 ;; f, and f = g to f - g and g - f. This is because cobyla expects
125 ;; all constraints to of the form h>=0.
126 (let (normalized-constraints)
127 (dolist (c (cdr constraints))
128 (let ((op ($op c)))
129 (cond ((string-equal op ">=")
130 (push (sub ($lhs c) ($rhs c)) normalized-constraints))
131 ((string-equal op "<=")
132 (push (sub ($rhs c) ($lhs c)) normalized-constraints))
133 ((string-equal op "=")
134 (push (sub ($lhs c) ($rhs c)) normalized-constraints)
135 (push (sub ($rhs c) ($lhs c)) normalized-constraints))
137 (merror "~M: Constraint equation must be =, <= or >=: got ~M"
138 %%pretty-fname op)))))
140 (setf normalized-constraints
141 (list* '(mlist)
142 (nreverse normalized-constraints)))
143 (when *debug-cobyla*
144 (mformat t "cons = ~M~%" normalized-constraints))
146 (let* ((n (length (cdr vars)))
147 (m (length (cdr normalized-constraints)))
148 (x (make-array n
149 :element-type 'double-float
150 :initial-contents
151 (mapcar #'(lambda (z)
152 (let ((r ($float z)))
153 (if (floatp r)
155 (merror "~M: Does not evaluate to a float: ~M"
156 %%pretty-fname z))))
157 (cdr init-x))))
158 ;; Real work array for cobyla.
159 (w (make-array (+ (* n (+ (* 3 n)
160 (* 2 m)
161 11))
162 (+ (* 4 m) 6)
164 :element-type 'double-float))
165 ;; Integer work array for cobyla.
166 (iact (make-array (+ m 1) :element-type 'f2cl-lib::integer4))
167 (fv (coerce-float-fun f vars))
168 (cv (coerce-float-fun normalized-constraints vars))
169 (*calcfc*
170 #'(lambda (nn mm xval cval)
171 ;; Compute the function and the constraints at
172 ;; the given xval. The function value is
173 ;; returned is returned, and the constraint
174 ;; values are stored in cval.
175 (declare (fixnum nn mm)
176 (type (cl:array cl:double-float (*)) xval cval))
177 (let* ((x-list (coerce xval 'list))
178 (f (apply fv x-list))
179 (c (apply cv x-list)))
180 ;; Do we really need these checks?
181 (unless (floatp f)
182 (merror "~M: The objective function did not evaluate to a number at ~M"
183 %%pretty-fname (list* '(mlist) x-list)))
184 (unless (every #'floatp (cdr c))
185 (let ((bad-cons
186 (loop for cval in (cdr c)
187 for k from 1
188 unless (floatp cval)
189 collect k)))
190 ;; List the constraints that did not
191 ;; evaluate to a number to make it easier
192 ;; for the user to figure out which
193 ;; constraints were bad.
194 (mformat t "~M: At the point ~M:~%"
195 %%pretty-fname (list* '(mlist) x-list))
196 (merror
197 (with-output-to-string (msg)
198 (loop for index in bad-cons
200 (mformat msg
201 "Constraint ~M: ~M did not evaluate to a number.~%"
202 index
203 (elt normalized-constraints index)))))))
204 (replace cval c :start2 1)
205 ;; This is the f2cl calling convention for
206 ;; CALCFC. For some reason, f2cl thinks n
207 ;; and m are modified, so they must be
208 ;; returned.
209 (values nn mm nil f nil)))))
210 (multiple-value-bind (null-0 null-1 null-2 null-3 null-4 null-5
211 neval null-6 null-7 ierr)
212 (cobyla:cobyla n m x rhobeg rhoend iprint maxfun w iact 0)
213 (declare (ignore null-0 null-1 null-2 null-3 null-4 null-5 null-6 null-7))
214 ;; Should we put a check here if the number of function
215 ;; evaluations equals maxfun? When iprint is not 0, the output
216 ;; from COBYLA makes it clear that something bad happened.
217 (let* ((x-list (coerce x 'list))
218 (soln (list* '(mlist)
219 (mapcar #'(lambda (var val)
220 `((mequal) ,var ,val))
221 (cdr vars)
222 (coerce x 'list))))
223 ;; The maxcv value. See cobyla.f MPP value. MPP = M +
224 ;; 2, adjusted for 0-indexing lisp arrays.
225 (max-cv (aref w (+ m 1))))
226 ;; Return a list off the following items:
227 ;; 1: The point that gives the optimum in the form var=val
228 ;; 2: The corresponding value of the function
229 ;; 3: Number of function evaluations
230 ;; 4: Return code
231 ;; 0 - no errors
232 ;; 1 - maxfun limit reached
233 ;; 2 - rounding issues
234 ;; -1 - maxcv exceeds rhoend probably indicating
235 ;; constraints not satisfied.
236 (make-mlist
237 soln
238 (apply fv x-list)
239 neval
240 (if (> max-cv rhoend) -1 ierr)))))))