├── nlopt.asd ├── LICENSE ├── package.lisp ├── utils.lisp ├── example.lisp ├── nloptimize.lisp ├── README.md ├── cffi.lisp └── nlopt.lisp /nlopt.asd: -------------------------------------------------------------------------------- 1 | ;;;; nlopt.asd 2 | 3 | (asdf:defsystem #:nlopt 4 | :description "Common Lisp interface to Non-linear optimization library NLopt" 5 | :author "Bibek Panthi " 6 | :license "MIT" 7 | :version "0.0.1" 8 | :serial t 9 | :depends-on (:cffi :trivial-garbage) 10 | :components ((:file "package") 11 | (:file "cffi") 12 | (:file "utils") 13 | (:file "nlopt") 14 | (:file "nloptimize"))) 15 | 16 | 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Bibek Panthi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /package.lisp: -------------------------------------------------------------------------------- 1 | ;;;; package.lisp 2 | 3 | (defpackage #:nlopt.cffi 4 | (:use #:cl)) 5 | 6 | (defpackage #:nlopt 7 | (:use #:cl) 8 | (:local-nicknames (:c :nlopt.cffi)) 9 | (:export #:copy 10 | #:algorithm 11 | #:dimensions 12 | #:algorithms 13 | #:algorithm-name 14 | #:create 15 | 16 | #:set-min-objective 17 | #:set-max-objective 18 | #:set-precond-min-objective 19 | #:set-precond-max-objective 20 | 21 | #:add-inequality-constraint 22 | #:add-equality-constraint 23 | #:remove-inequality 24 | #:remove-equality 25 | #:add-inequality-mconstraints 26 | #:add-equality-mconstraints 27 | 28 | #:lower-bounds 29 | #:upper-bounds 30 | #:lower-bound 31 | #:upper-bound 32 | 33 | #:stopval 34 | #:ftol-rel 35 | #:ftol-abs 36 | #:xtol-rel 37 | #:x-weights 38 | #:xtol-abs 39 | #:maxeval 40 | #:maxtime 41 | #:numevals 42 | 43 | #:force-stop 44 | #:force-stop-value 45 | 46 | #:optimize-nlopt 47 | #:nloptimize 48 | #:set-local-optimizer 49 | 50 | #:initial-step 51 | #:set-population 52 | #:srand 53 | #:srand-time 54 | #:vector-storage 55 | 56 | #:result-description 57 | #:version)) 58 | -------------------------------------------------------------------------------- /utils.lisp: -------------------------------------------------------------------------------- 1 | (in-package :nlopt) 2 | 3 | (defmacro ensure-success (&body body) 4 | `(assert (eql :nlopt_success (progn ,@body)))) 5 | 6 | (deftype doubles () 7 | "Array of double floats" 8 | '(array double-float *)) 9 | 10 | (defun doubles (list) 11 | "Create an array of double floats from given `list' of double floats" 12 | (make-array (length list) :element-type 'double-float 13 | :initial-contents list)) 14 | 15 | (defun doubles* (list) 16 | "Create an array of double floats from given `list' (coerces numbers to double-float)" 17 | (make-array (length list) :element-type 'double-float 18 | :initial-contents (loop for x in list 19 | collect (coerce x 'double-float)))) 20 | 21 | (defun doubles-array (size initial-element) 22 | "Create oan array of double floats of `size' with `initial-element'" 23 | (make-array size :element-type 'double-float 24 | :initial-element initial-element)) 25 | 26 | (defun doubles-array* (size initial-element) 27 | "Create oan array of double floats of `size' with `initial-element' (coerces `initial-element' to double-float)" 28 | (make-array size :element-type 'double-float 29 | :initial-element (coerce initial-element 'double-float))) 30 | 31 | (declaim (inline dref)) 32 | (defun dref (ptr index) 33 | "Return element of foreign double float array (`ptr') at `index' position" 34 | (cffi:mem-aref ptr :double index)) 35 | 36 | (defun (setf dref) (val ptr index) 37 | "Set element of foreign double float array `ptr' at `index' to value `val'" 38 | (setf (cffi:mem-aref ptr :double index) val)) 39 | 40 | (defun setf-doubles2 (ptr data) 41 | "Set elements of a foreign array of doubles" 42 | (loop for d double-float in data 43 | for i integer from 0 do 44 | (setf (cffi:mem-aref ptr :double i) d))) 45 | 46 | (defun setf-doubles (ptr &rest data) 47 | "Set elements of a foreign array of doubles" 48 | (loop for d double-float in data 49 | for i integer from 0 do 50 | (setf (cffi:mem-aref ptr :double i) d))) 51 | 52 | (defun %dreffing@ (var expr) 53 | (cond ((atom expr) 54 | (if (and (symbolp expr) 55 | (char-equal #\@ (aref (symbol-name expr) 0))) 56 | `(dref ,var ,(parse-integer (symbol-name expr) :start 1)) 57 | expr)) 58 | ((listp expr) 59 | (cons (first expr) (mapcar (lambda (e) (%dreffing@ var e)) (rest expr)))))) 60 | 61 | (defmacro dreffing@ (x &body body) 62 | "replace occurance of @n with (dref x n) in body 63 | Usefull for avoiding " 64 | `(progn ,@(mapcar (lambda (e) (%dreffing@ x e)) 65 | body))) 66 | 67 | (defun foreign-darray-to-lisp (ptr) 68 | (cffi:foreign-array-to-lisp ptr 'double-float)) 69 | 70 | (defmacro with-vector-ptr-to (vector &body body) 71 | (assert (symbolp vector)) 72 | `(if ,vector 73 | (cffi:with-pointer-to-vector-data (,vector ,vector) 74 | ,@body) 75 | (let ((,vector (cffi:null-pointer))) 76 | ,@body))) 77 | -------------------------------------------------------------------------------- /example.lisp: -------------------------------------------------------------------------------- 1 | (in-package :nlopt) 2 | 3 | (defun example1 () 4 | "Finds minima of f(x) = (x+3)^2" 5 | (let ((nlopt (create :nlopt_ld_mma 1))) 6 | (setf (lower-bounds nlopt) '(0d0)) 7 | (set-min-objective nlopt (lambda (x grad nlopt) 8 | (declare (ignore nlopt)) 9 | (when grad 10 | (setf (dref grad 0) (* 2 (+ 3d0 (dref x 0))))) 11 | (expt (+ 3d0 (dref x 0)) 2))) 12 | (setf (xtol-abs nlopt) 1d-4) 13 | (optimize-nlopt nlopt '(10d0)))) 14 | 15 | (defun example1-nloptimize () 16 | (nloptimize ((x) :initial '(10d0)) 17 | (:minimize (expt x 2)) 18 | (:satisfy (> x 0)) 19 | (setf (xtol-abs *nlopt-instance*) 1d-4))) 20 | 21 | (defun example-mma() 22 | "The https://nlopt.readthedocs.io/en/latest/NLopt_Tutorial/ problem 23 | minimize sqrt(y) 24 | subject to 25 | y >= (2x)^3 26 | y >= (1 - x)^3 27 | y>0" 28 | (let ((nlopt (create :nlopt_ld_mma 2))) 29 | (setf (lower-bound nlopt 1) 0d0) 30 | (set-min-objective nlopt (lambda (x grad nlopt) 31 | (declare (ignore nlopt)) 32 | (let ((sqrtx1 (sqrt (dref x 1)))) 33 | (when grad 34 | (setf-doubles grad 35 | 0.0d0 36 | (/ 0.5d0 sqrtx1))) 37 | sqrtx1))) 38 | (add-inequality-constraint nlopt 39 | (lambda (x grad nlopt) 40 | (declare (ignore nlopt)) 41 | (let ((x0 (dref x 0)) 42 | (x1 (dref x 1))) 43 | (setf-doubles grad 44 | (* 6 (expt (* 2 x0) 2)) 45 | -1d0) 46 | (- (expt (* 2 x0) 3) x1))) 47 | 1d-2) 48 | (add-inequality-constraint nlopt 49 | (lambda (x grad nlopt) 50 | (declare (ignore nlopt)) 51 | (let ((x0 (dref x 0)) 52 | (x1 (dref x 1))) 53 | (setf-doubles grad 54 | (* -3 (expt (+ (- x0) 1d0) 2)) 55 | -1d0) 56 | (- (expt (+ (- x0) 1) 3) x1))) 57 | 1d-2) 58 | (setf (xtol-rel nlopt) 1d-4) 59 | (optimize-nlopt nlopt (doubles (list 1.234d0 5.678d0))))) 60 | 61 | (defun example2 () 62 | "Same problem as (example-mma) 63 | The https://nlopt.readthedocs.io/en/latest/NLopt_Tutorial/ problem 64 | minimize sqrt(y) 65 | subject to 66 | y >= (2x)^3 67 | y >= (1 - x)^3 68 | y>0" 69 | (nloptimize ((x y) 70 | :initial '(1.234 5.678)) 71 | (:minimize (sqrt y)) 72 | (:satisfy (>= y (expt (* 2 x) 3)) 73 | (>= y (expt (- 1 x) 3)) 74 | (> y 0)) 75 | (setf (xtol-rel *nlopt-instance*) 1d-4))) 76 | 77 | (defun example3 () 78 | (let ((nlopt (create :nlopt_ln_cobyla 5))) 79 | (set-min-objective nlopt 80 | (lambda (x grad nlopt) 81 | (declare (ignore grad nlopt)) 82 | (dreffing@ x 83 | (+ @0 @1 @2 @3 @4)))) 84 | (setf (lower-bounds nlopt) -10d0) 85 | (setf (xtol-rel nlopt) 1d-4) 86 | (add-equality-mconstraint nlopt 3 87 | (lambda (x grad nlopt) 88 | (declare (ignore grad nlopt)) 89 | (dreffing@ x 90 | (list (+ @0 (* @1 @2)) 91 | (- @3 (/ @4 @2)) 92 | (/ @1 (* @0 @1))))) 93 | 0.001) 94 | (optimize-nlopt nlopt 1))) 95 | -------------------------------------------------------------------------------- /nloptimize.lisp: -------------------------------------------------------------------------------- 1 | (in-package :nlopt) 2 | 3 | ;;;;; High Level nloptimize macro 4 | 5 | (eval-when (:compile-toplevel :load-toplevel :execute) 6 | (defun filter-visible-vars (vars body &optional sofar) 7 | "Returns list of `vars' that are seen in `body' 8 | results found are stored in `sofar'" 9 | (cond ((null body) sofar) 10 | ((symbolp body) 11 | (if (and (find body vars) 12 | (not (find body sofar))) 13 | (cons body sofar) 14 | sofar)) 15 | ((not (listp body)) sofar) 16 | ((eql (first body) 'quote) sofar) 17 | (t (dolist (el (rest body) sofar) 18 | (setf sofar (filter-visible-vars vars el sofar)))))) 19 | 20 | (defun no-visible-vars? (vars exp) 21 | ;; TODO write a more efficient function 22 | (not (filter-visible-vars vars exp))) 23 | 24 | (defun %with-nlopt-lambda (vars expression) 25 | (alexandria:with-gensyms (x grad nlopt) 26 | (let* ((found (filter-visible-vars vars expression)) 27 | (bindings (loop for v in found 28 | collect (list v (list 'dref x (position v vars)))))) 29 | (if bindings 30 | `(lambda (,x ,grad ,nlopt) 31 | (declare (ignore ,grad ,nlopt)) 32 | (let ,bindings 33 | ,expression)) 34 | `(progn () 35 | (warn "The expression ~%~a~% doesn't depend on the nlopt parameters ~%" expression vars) 36 | `(lambda (,x ,grad, ,nlopt) 37 | (declare (ignore ,grad ,nlopt)) 38 | ,expression)))))) 39 | 40 | (defun %with-nlopt-optimize (vars type functions) 41 | "Return code for optimizing (first functions)" 42 | (unless (= 1 (length functions)) 43 | (error ":minimize or :maximize take only one expression ~a" functions)) 44 | (ecase type 45 | (:minimize `(set-min-objective *nlopt-instance* 46 | ,(%with-nlopt-lambda vars (first functions)))) 47 | (:maximize `(set-max-objective *nlopt-instance* 48 | ,(%with-nlopt-lambda vars (first functions)))))) 49 | 50 | 51 | (defun %with-nlopt-inequality-constraint (vars exp) 52 | "constaints of type (< (- (* 2 x) 5) (* 2 y) z 10) 53 | input `exp' should not contain inequality sign" 54 | (assert (> (length exp) 1) (exp)) 55 | (loop 56 | with code = nil 57 | for l in exp 58 | for g in (rest exp) do 59 | ;; handle expressions of form l < g 60 | (cond 61 | ;; x < const 62 | ((and (member l vars) (no-visible-vars? vars g)) 63 | (push `(setf (upper-bound *nlopt-instance* ,(position l vars)) ,g) code)) 64 | ;; const < x 65 | ((and (no-visible-vars? vars l) (member g vars)) 66 | (push `(setf (lower-bound *nlopt-instance* ,(position g vars)) ,l) code)) 67 | ;; const < const 68 | ((and (no-visible-vars? vars l) (no-visible-vars? vars g)) 69 | (error "~a < ~a inequality doesn't involve any of the declared parameters ~a" l g vars)) 70 | ;; x < f(vars), f(vars) < g(vars), f(vars) < x i.e. l - g < 0 71 | (t 72 | (push `(add-inequality-constraint *nlopt-instance* 73 | ,(%with-nlopt-lambda vars (list '- l g))) 74 | code))) 75 | finally (return (reverse code)))) 76 | 77 | (defun %with-nlopt-constraints (vars exp) 78 | (cond ((member (first exp) '(> < <= >=)) 79 | ;; inequality constraint (<) 80 | (if (or (eql (first exp) '>) (eql (first exp) '>=)) 81 | (setf exp (reverse (rest exp))) 82 | (setf exp (rest exp))) 83 | (let ((code (%with-nlopt-inequality-constraint vars exp))) 84 | (if (= 1 (length code)) ;; single expression 85 | (first code) 86 | `(progn ,@code)))) 87 | (t ;; equality constraint 88 | `(add-equality-constraint *nlopt-instance* ,(%with-nlopt-lambda vars exp))))) 89 | 90 | (defun %with-nlopt-satisfy (vars body) 91 | `(progn 92 | ,@(loop for exp in body 93 | collect (%with-nlopt-constraints vars exp)))) 94 | 95 | (defun %with-nlopt-walker (vars body) 96 | "Walk the body and replace :minimize, :maximize and :satisfy with proper code" 97 | (cond ((null body) nil) 98 | ((not (listp body)) body) 99 | 100 | ((eql (first body) 'quote) body) 101 | ((keywordp (first body)) 102 | (ecase (first body) 103 | (:minimize (%with-nlopt-optimize vars :minimize (rest body))) 104 | (:maximize (%with-nlopt-optimize vars :maximize (rest body))) 105 | (:satisfy (%with-nlopt-satisfy vars (rest body))))) 106 | (t (mapcar #'(lambda (exp) (%with-nlopt-walker vars exp)) body)))) 107 | 108 | (defmacro nloptimize ((vars &key (algorithm :nlopt_ln_cobyla) (initial '(1 1 1))) &body body) 109 | "Quick and easy way to solve an optimization problem 110 | `vars' is list of symbols for variables/parameter names 111 | `algorithm' is the algorithm used for solving. It must be a non-gradient algorithm :nlopt_ln_* or :nlopt_gn_* 112 | `initial' is the initial values used for parameters 113 | `body' can contain normal lisp code however the `body' is parsed for following covenience forms 114 | (:minimize expr) (:maximize expr) ;; sets the objective function 115 | (:satisfy expr1 expr2 ...) ;; adds constraints 116 | each constraint can be of the form 117 | (+|- ...) ;; an equality constraint expr = 0 118 | (<|<=|>|>= ...) ;; an inequality constraint or bounds on the parameter 119 | inside the body `*nlopt-instance*' can be used to refer to current nlopt instance" 120 | 121 | `(let ((*nlopt-instance* (create ,algorithm ,(length vars)))) 122 | ,@(%with-nlopt-walker vars body) 123 | (optimize-nlopt *nlopt-instance* (doubles* ,initial))))) 124 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nlopt (Common Lisp NLopt Bindings) 2 | 3 | This is a Common Lisp interface to NLopt. NLopt is a free/open-source library for nonlinear optimization, providing a common interface for a number of different free optimization routines 4 | available online as well as original implementations of various other algorithms. See [link](https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/) for more information on the available algorithms. 5 | 6 | ## Use 7 | 8 | 1) For usual cases the simple and easy `nloptimize` macro suffices: 9 | ```common-lisp 10 | (defun solve () 11 | (nloptimize ((x y) 12 | :initial '(1.234 5.678)) 13 | (:minimize (sqrt y)) 14 | (:satisfy (>= y (expt (* 2 x) 3)) 15 | (>= y (expt (- 1 x) 3)) 16 | (> y 0)) 17 | (setf (xtol-rel *nlopt-instance*) 1d-4))) 18 | ``` 19 | The above example minimizes `sqrt(y)` subject to `y >= (2x)^3`, `y >= (1 - x)^3` and `y>0` with initial guess for `(x,y)` at `(1.234, 5.678)` (This is the tutorial problem given [here](https://nlopt.readthedocs.io/en/latest/NLopt_Tutorial/)). 20 | 21 | 22 | 2) Or you can use functions equivalent to those defined in original NLopt C library. 23 | ```common-lisp 24 | (defun solve () 25 | (let ((nlopt (create :nlopt_ld_mma 2))) 26 | (set-lower-bounds nlopt (doubles -11d0 0.001d0)) 27 | (set-min-objective nlopt objective-function) 28 | (add-inequality-constraint nlopt constraint1) 29 | (add-inequality-constraint nlopt constraint2) 30 | (set-xtol-rel nlopt 1d-4) 31 | (optimize-nlp nlopt (darray 1.234d0 5.67d0)))) 32 | ``` 33 | First you create a nlopt object representing the optimization problem by specifying the algorithm to use and the dimension (number of variables) of the problem. 34 | 35 | ```common-lisp 36 | (create algorithm dimension) 37 | ``` 38 | Then you add objective function, constraints, bounds, stopping criteria, etc to the problem. E.g. 39 | ```common-lisp 40 | (defun objective-function (x grad nlopt) 41 | (setf-doubles grad grad_0 grad_1 grad_2 ...) 42 | objective-function-value-at-x) 43 | 44 | (set-min-objective nlopt objective-function)) 45 | ``` 46 | Here an objective to minimize the function (objective-function) is set. 47 | This callback function (or lambdas can also be used) accepts the value of variables (x) in an foreign-array of double-float. Elements of x can be accessed by using `(dref x index)` function. 48 | Also if the algorithm selected requires the gradient of the function to be computed then grad is set to a pointer to the foreign-array where calculated values have to set. 49 | You can use `(setf (dref grad 0) value0 (dref grad 1) value1 ...)` or `(set-doubles grad value0 value1 ...)`. If the algorithm doesn't require gradient to be calculated then `grad` is NIL. 50 | The current `nlopt` object is also passed to the callback. 51 | 52 | ## Examples 53 | Few examples are available in examples.lisp file. It may be helpful to follow along the [original tutorial](https://nlopt.readthedocs.io/en/latest/NLopt_Tutorial/) along with its implementation in lisp given in example.lisp file `(example-mma)` 54 | 55 | ## Installation 56 | ### Install the NLopt shared library to your system 57 | #### Linux 58 | Ubuntu 59 | ```bash 60 | apt install nlopt 61 | ``` 62 | Arch 63 | ```bash 64 | pacman -Suy nlopt 65 | ``` 66 | 67 | #### Windows 68 | Download the prebuilt binary from [here](https://nlopt.readthedocs.io/en/latest/NLopt_on_Windows/) 69 | and copy the libnlopt.dll to any folder in your PATH (e.g. c:/Windows/System32/) or to this project's directory 70 | 71 | ### Install this library 72 | Download or clone this repo to your `local-projects' directory then load it. 73 | ```common-lisp 74 | (ql:quickload :nlopt) 75 | ``` 76 | 77 | 78 | ## Conventions 79 | You can read the documentation of NLopt C library [here](https://nlopt.readthedocs.io/en/latest/NLopt_Reference/). This Common Lisp binding to the NLopt library tries to follow the 80 | names of the original functions albiet with some lispier modifications. Let's see few example: 81 | 82 | ```c 83 | nlopt_create(nlopt_algorithm algorithm, unsigned n); 84 | ``` 85 | is available as 86 | ```common-lisp 87 | (create algorithm n) 88 | ``` 89 | The nlopt prefix is removed because all functions are in nlopt package. So, you may access them from any other package as `(nlopt:create algorithm n)` 90 | 91 | ```c 92 | nlopt_set_min_objective(nlopt_opt opt, nlopt_func f, void* f_data); 93 | ``` 94 | is available as 95 | ```common-lisp 96 | (set-min-objective nlopt function) 97 | ``` 98 | The nlopt prefix is removed and all underscores are converted to hypens. Also notice that, the function doesn't take a `f_data` struct to pass along the callbacks. 99 | Because in Common Lisp we can use dynamic binding to set the contex. Also, instead of `f_data`, the nlopt instance is passed along in the callbacks. So, you may create a subclass of nlopt if you need 100 | to store some state to use in the callbacks. 101 | 102 | The callback for the objective function 103 | ```c 104 | double f(unsigned n, const double* x, double* grad, void* f_data); 105 | ``` 106 | should be defined as 107 | ```common-lisp 108 | (defun f(x grad nlopt) ...) 109 | ``` 110 | As mentioned above instead of a user defined data `f_data`, the `nlopt` instance is passed. Also note that parameter indicating dimension (`n`) as also unnecessary because 111 | it is available through the `nlopt` object as : `n` = ` (dimension nlopt)`. 112 | 113 | 114 | Signature for callbacks to other functions are documented in the docstring of respective functions (`set-min-objective`, `set-inequality-constraints`, ...) 115 | 116 | Since `optimize` is a reserved word in Common Lisp, `c 117 | nlopt_optimize(nlopt_opt opt, double *x, double *opt_f);` is avaibale as 118 | `commmon-lisp 119 | (optimize-nlp nlopt initial-x)`. Since functions can return multiples values, the `opt_f` pointer is not required to get the optimum value. `optimize` returns the optimum position `x` and the optimum value `f(x)`. 120 | 121 | 122 | Functions that have `set-foo` and `get-foo` counterparts are defined as `(setf (foo ...) value)` and `(foo ...)` 123 | 124 | All other functions are name similarly. 125 | ### The NLopt Object 126 | | NLopt | Common Lisp Binding | 127 | |-----------------------------------------------------|------------------------------| 128 | | nlopt_create(nlopt_algorithm algorithm, unsigned n) | (create algorithm dimension) | 129 | | nlopt_copy(const nlopt_opt opt) | (copy nlopt) | 130 | | nlopt_get_algorithm(const nlopt_opt opt); | (algorithm nlopt) | 131 | | nlopt_get_dimension(const nlopt_opt opt); | (dimensions nlopt) | 132 | | nlopt_algorithm_name(nlopt_algorithm algorithm); | (algorithm-name algorithm) | 133 | 134 | ### Objective Function 135 | | NLopt | Common Lisp Binding | 136 | |------------------------------------------------------------------------------------------------|------------------------------------------------| 137 | | nlopt_set_min_objective(nlopt_opt opt, nlopt_func f, void* f_data); | (set-min-objective nlopt function) | 138 | | nlopt_set_max_objective(nlopt_opt opt, nlopt_func f, void* f_data); | (set-max-objective nlopt function) | 139 | | nlopt_set_precond_min_objective(nlopt_opt opt, nlopt_func f, nlopt_precond pre, void *f_data); | (set-precond-min-objective nlopt function pre) | 140 | | nlopt_set_precond_min_objective(nlopt_opt opt, nlopt_func f, nlopt_precond pre, void *f_data); | (set-precond-max-objective nlopt function pre) | 141 | 142 | ### Constraints and Bounds 143 | | NLopt | Common Lisp Binding | 144 | |--------------------------------------------------------------------------------------------------------------|---------------------------------------------------| 145 | | nlopt_add_inequality_constraint(nlopt_opt opt, nlopt_func fc, void* fc_data, double tol); | (add-inequality-constraint nlopt function tol) | 146 | | nlopt_add_equality_constraint(nlopt_opt opt, nlopt_func h, void* h_data, double tol); | (add-equality-constraint nlopt function tol) | 147 | | nlopt_remove_inequality_constraints(nlopt_opt opt); | (remove-inequality-constraint nlopt) | 148 | | nlopt_remove_equality_constraints(nlopt_opt opt); | (remove-equality-constraint nlopt) | 149 | | nlopt_add_inequality_mconstraint(nlopt_opt opt, unsigned m, nlopt_mfunc c, void* c_data, const double *tol); | (add-inequality-mconstraint nlopt m function tol) | 150 | | nlopt_add_equality_mconstraint(nlopt_opt opt, unsigned m, nlopt_mfunc c, void* c_data, const double *tol); | (add-equality-mconstraint nlopt m function tol) | 151 | | nlopt_set_lower_bounds(nlopt_opt opt, const double* lb); | (setf (lower-bounds nlopt) bounds) | 152 | | nlopt_set_upper_bounds(nlopt_opt opt, const double* ub); | (setf (upper-bounds nlopt) bounds) | 153 | | nlopt_set_lower_bounds1(nlopt_opt opt, double lb); | (setf (lower-bounds nlopt) bound) | 154 | | nlopt_set_upper_bounds1(nlopt_opt opt, double ub); | (setf (upper-bounds nlopt) bound) | 155 | | nlopt_get_lower_bounds(const nlopt_opt opt, double* lb); | (lower-bounds nlopt) | 156 | | nlopt_get_upper_bounds(const nlopt_opt opt, double* ub); | (upper-bounds nlopt) | 157 | | nlopt_set_lower_bound(nlopt_opt opt, int i, double lb); | (setf (lower-bound nlopt i) bound) | 158 | | nlopt_set_upper_bound(nlopt_opt opt, int i, double ub); | (setf (upper-bound nlopt i) bound) | 159 | | | (lower-bound nlopt i) | 160 | | | (upper-bound nlopt i) | 161 | 162 | ### Stopping Criteria 163 | | NLopt | Common Lisp Binding | 164 | |-------------------------------------------------------|----------------------------------| 165 | | nlopt_set_stopval(nlopt_opt opt, double stopval); | (setf (stopval nlopt) stopval) | 166 | | nlopt_get_stopval(const nlopt_opt opt); | (stopval nlopt) | 167 | | nlopt_set_ftol_rel(nlopt_opt opt, double tol); | (setf (ftol-rel nlopt) tol) | 168 | | nlopt_get_ftol_rel(const nlopt_opt opt); | (ftol-rel nlopt) | 169 | | nlopt_set_ftol_abs(nlopt_opt opt, double tol); | (setf (ftol-abs nlopt) tol) | 170 | | nlopt_get_ftol_abs(const nlopt_opt opt); | (ftol-abs nlopt) | 171 | | nlopt_set_xtol_rel(nlopt_opt opt, double tol); | (setf (xtol-rel nlopt) tol) | 172 | | nlopt_get_xtol_rel(const nlopt_opt opt); | (xtol-rel nlopt) | 173 | | nlopt_set_x_weights(nlopt_opt opt, const double *w); | (setf (x-weights nlopt) weights) | 174 | | nlopt_set_x_weights1(nlopt_opt opt, const double w); | (setf (x-weights nlopt) weight) | 175 | | nlopt_get_x_weights(const nlopt_opt opt, double *w); | (x-weights nlopt) | 176 | | nlopt_set_xtol_abs(nlopt_opt opt, const double *tol); | (setf (xtol-abs nlopt) tol) | 177 | | nlopt_set_xtol_abs1(nlopt_opt opt, double tol); | (setf (xtol-abs nlopt) tol) | 178 | | nlopt_get_xtol_abs(const nlopt_opt opt, double *tol); | (xtol-abs nlopt) | 179 | | nlopt_set_maxeval(nlopt_opt opt, int maxeval); | (setf (maxval nlopt) maxeval) | 180 | | nlopt_get_maxeval(nlopt_opt opt); | (maxeval nlopt) | 181 | | nlopt_set_maxtime(nlopt_opt opt, double maxtime); | (setf (maxtime nlopt) maxtime) | 182 | | nlopt_get_maxtime(nlopt_opt opt); | (maxtime nlopt) | 183 | | nlopt_get_numevals(nlopt_opt opt); | (numevals nlopt) | 184 | 185 | ### Forced Termination 186 | | NLopt | Common Lisp Binding | 187 | |----------------------------------------------|-------------------------------------| 188 | | nlopt_force_stop(nlopt_opt opt); | (force-stop nlopt) | 189 | | nlopt_set_force_stop(nlopt_opt opt, int val) | (setf (force-stop-value nlopt) val) | 190 | | nlopt_get_force_stop(nlopt_opt opt) | (force-stop-value nlopt) | 191 | 192 | ### Optimization 193 | | NLopt | Common Lisp Binding | 194 | |----------------------------------------------------------------------|-----------------------------------------| 195 | | nlopt_optimize(nlopt_opt opt, double *x, double *opt_f); | (optimize-nlopt nlopt x) | 196 | | nlopt_set_local_optimizer(nlopt_opt opt, const nlopt_opt local_opt); | (set-local-optimizer nlopt local-nlopt) | 197 | 198 | ### Others 199 | | NLopt | Common Lisp Binding | 200 | |---------------------------------------------------------------------------|---------------------------------| 201 | | nlopt_set_initial_step(nlopt_opt opt, const double* dx); | (setf (initial-step nlopt) dx) | 202 | | nlopt_set_initial_step1(nlopt_opt opt, const double dx); | (setf (initial-step nlopt) dx) | 203 | | nlopt_get_initial_step(const nlopt_opt opt, const double *x, double *dx); | (initila-step nlopt) | 204 | | nlopt_set_population(nlopt_opt opt, unsigned pop); | (set-population nlopt size) | 205 | | nlopt_srand(unsigned long seed); | (srand seed) | 206 | | nlopt_srand_time(void); | (srand-time) | 207 | | nlopt_set_vector_storage(nlopt_opt opt, unsigned M); | (setf (vector-storage nlopt) M) | 208 | | nlopt_get_vector_storage(const nlopt_opt opt); | (vector-storage nlopt) | 209 | | nlopt_version(int *major, int *minor, int *bugfix); | (version) | 210 | 211 | ## License 212 | MIT 213 | -------------------------------------------------------------------------------- /cffi.lisp: -------------------------------------------------------------------------------- 1 | (in-package :nlopt.cffi) 2 | 3 | (cl:export 'nlopt_algorithm) 4 | (cffi:defcenum nlopt_algorithm 5 | (:NLOPT_GN_DIRECT #.0) 6 | :NLOPT_GN_DIRECT_L 7 | :NLOPT_GN_DIRECT_L_RAND 8 | :NLOPT_GN_DIRECT_NOSCAL 9 | :NLOPT_GN_DIRECT_L_NOSCAL 10 | :NLOPT_GN_DIRECT_L_RAND_NOSCAL 11 | :NLOPT_GN_ORIG_DIRECT 12 | :NLOPT_GN_ORIG_DIRECT_L 13 | :NLOPT_GD_STOGO 14 | :NLOPT_GD_STOGO_RAND 15 | :NLOPT_LD_LBFGS_NOCEDAL 16 | :NLOPT_LD_LBFGS 17 | :NLOPT_LN_PRAXIS 18 | :NLOPT_LD_VAR1 19 | :NLOPT_LD_VAR2 20 | :NLOPT_LD_TNEWTON 21 | :NLOPT_LD_TNEWTON_RESTART 22 | :NLOPT_LD_TNEWTON_PRECOND 23 | :NLOPT_LD_TNEWTON_PRECOND_RESTART 24 | :NLOPT_GN_CRS2_LM 25 | :NLOPT_GN_MLSL 26 | :NLOPT_GD_MLSL 27 | :NLOPT_GN_MLSL_LDS 28 | :NLOPT_GD_MLSL_LDS 29 | :NLOPT_LD_MMA 30 | :NLOPT_LN_COBYLA 31 | :NLOPT_LN_NEWUOA 32 | :NLOPT_LN_NEWUOA_BOUND 33 | :NLOPT_LN_NELDERMEAD 34 | :NLOPT_LN_SBPLX 35 | :NLOPT_LN_AUGLAG 36 | :NLOPT_LD_AUGLAG 37 | :NLOPT_LN_AUGLAG_EQ 38 | :NLOPT_LD_AUGLAG_EQ 39 | :NLOPT_LN_BOBYQA 40 | :NLOPT_GN_ISRES 41 | :NLOPT_AUGLAG 42 | :NLOPT_AUGLAG_EQ 43 | :NLOPT_G_MLSL 44 | :NLOPT_G_MLSL_LDS 45 | :NLOPT_LD_SLSQP 46 | :NLOPT_LD_CCSAQ 47 | :NLOPT_GN_ESCH 48 | :NLOPT_NUM_ALGORITHMS) 49 | 50 | (export 'algorithm_name) 51 | (cffi:defcfun ("nlopt_algorithm_name" algorithm_name) :string 52 | (a nlopt_algorithm)) 53 | 54 | (export 'nlopt_result) 55 | (cffi:defcenum nlopt_result 56 | (:NLOPT_FAILURE #.-1) 57 | (:NLOPT_INVALID_ARGS #.-2) 58 | (:NLOPT_OUT_OF_MEMORY #.-3) 59 | (:NLOPT_ROUNDOFF_LIMITED #.-4) 60 | (:NLOPT_FORCED_STOP #.-5) 61 | (:NLOPT_SUCCESS #.1) 62 | (:NLOPT_STOPVAL_REACHED #.2) 63 | (:NLOPT_FTOL_REACHED #.3) 64 | (:NLOPT_XTOL_REACHED #.4) 65 | (:NLOPT_MAXEVAL_REACHED #.5) 66 | (:NLOPT_MAXTIME_REACHED #.6)) 67 | 68 | (export 'result_to_string) 69 | (cffi:defcfun ("nlopt_result_to_string" result_to_string) :string 70 | (a nlopt_result)) 71 | 72 | (export 'result_from_string) 73 | (cffi:defcfun ("nlopt_result_from_string" result_from_string) nlopt_result 74 | (name :string)) 75 | 76 | (export 'srand) 77 | (cffi:defcfun ("nlopt_srand" srand) :void 78 | (seed :unsigned-long)) 79 | 80 | (export 'srand_time) 81 | (cffi:defcfun ("nlopt_srand_time" srand_time) :void) 82 | 83 | (export 'version) 84 | (cffi:defcfun ("nlopt_version" version) :void 85 | (major :pointer) 86 | (minor :pointer) 87 | (bugfix :pointer)) 88 | 89 | (export 'create) 90 | (cffi:defcfun ("nlopt_create" create) :pointer 91 | (algorithm nlopt_algorithm) 92 | (n :unsigned-int)) 93 | 94 | (export 'destroy) 95 | (cffi:defcfun ("nlopt_destroy" destroy) :void 96 | (opt :pointer)) 97 | 98 | (export 'copy) 99 | (cffi:defcfun ("nlopt_copy" copy) :pointer 100 | (opt :pointer)) 101 | 102 | (export 'optimize_nlp) 103 | (cffi:defcfun ("nlopt_optimize" optimize_nlp) nlopt_result 104 | (opt :pointer) 105 | (x :pointer) 106 | (opt_f :pointer)) 107 | 108 | (export 'set_min_objective) 109 | (cffi:defcfun ("nlopt_set_min_objective" set_min_objective) nlopt_result 110 | (opt :pointer) 111 | (f :pointer) 112 | (f_data :pointer)) 113 | 114 | (export 'set_max_objective) 115 | (cffi:defcfun ("nlopt_set_max_objective" set_max_objective) nlopt_result 116 | (opt :pointer) 117 | (f :pointer) 118 | (f_data :pointer)) 119 | 120 | (export 'set_precond_min_objective) 121 | (cffi:defcfun ("nlopt_set_precond_min_objective" set_precond_min_objective) nlopt_result 122 | (opt :pointer) 123 | (f :pointer) 124 | (pre :pointer) 125 | (f_data :pointer)) 126 | 127 | (export 'set_precond_max_objective) 128 | (cffi:defcfun ("nlopt_set_precond_max_objective" set_precond_max_objective) nlopt_result 129 | (opt :pointer) 130 | (f :pointer) 131 | (pre :pointer) 132 | (f_data :pointer)) 133 | 134 | (export 'get_algorithm) 135 | (cffi:defcfun ("nlopt_get_algorithm" get_algorithm) nlopt_algorithm 136 | (opt :pointer)) 137 | 138 | (export 'get_dimension) 139 | (cffi:defcfun ("nlopt_get_dimension" get_dimension) :unsigned-int 140 | (opt :pointer)) 141 | 142 | (export 'set_lower_bounds) 143 | (cffi:defcfun ("nlopt_set_lower_bounds" set_lower_bounds) nlopt_result 144 | (opt :pointer) 145 | (lb :pointer)) 146 | 147 | (export 'set_lower_bounds1) 148 | (cffi:defcfun ("nlopt_set_lower_bounds1" set_lower_bounds1) nlopt_result 149 | (opt :pointer) 150 | (lb :double)) 151 | 152 | (export 'set_lower_bound) 153 | (cffi:defcfun ("nlopt_set_lower_bound" set_lower_bound) nlopt_result 154 | (opt :pointer) 155 | (i :int) 156 | (lb :double)) 157 | 158 | 159 | (export 'set_upper_bound) 160 | (cffi:defcfun ("nlopt_set_upper_bound" set_upper_bound) nlopt_result 161 | (opt :pointer) 162 | (i :int) 163 | (lb :double)) 164 | 165 | (export 'get_lower_bounds) 166 | (cffi:defcfun ("nlopt_get_lower_bounds" get_lower_bounds) nlopt_result 167 | (opt :pointer) 168 | (lb :pointer)) 169 | 170 | (export 'set_upper_bounds) 171 | (cffi:defcfun ("nlopt_set_upper_bounds" set_upper_bounds) nlopt_result 172 | (opt :pointer) 173 | (ub :pointer)) 174 | 175 | (export 'set_upper_bounds1) 176 | (cffi:defcfun ("nlopt_set_upper_bounds1" set_upper_bounds1) nlopt_result 177 | (opt :pointer) 178 | (ub :double)) 179 | 180 | (export 'get_upper_bounds) 181 | (cffi:defcfun ("nlopt_get_upper_bounds" get_upper_bounds) nlopt_result 182 | (opt :pointer) 183 | (ub :pointer)) 184 | 185 | (export 'remove_inequality_constraints) 186 | (cffi:defcfun ("nlopt_remove_inequality_constraints" remove_inequality_constraints) nlopt_result 187 | (opt :pointer)) 188 | 189 | (export 'add_inequality_constraint) 190 | (cffi:defcfun ("nlopt_add_inequality_constraint" add_inequality_constraint) nlopt_result 191 | (opt :pointer) 192 | (fc :pointer) 193 | (fc_data :pointer) 194 | (tol :double)) 195 | 196 | (export 'add_precond_inequality_constraint) 197 | (cffi:defcfun ("nlopt_add_precond_inequality_constraint" add_precond_inequality_constraint) nlopt_result 198 | (opt :pointer) 199 | (fc :pointer) 200 | (pre :pointer) 201 | (fc_data :pointer) 202 | (tol :double)) 203 | 204 | (export 'add_inequality_mconstraint) 205 | (cffi:defcfun ("nlopt_add_inequality_mconstraint" add_inequality_mconstraint) nlopt_result 206 | (opt :pointer) 207 | (m :unsigned-int) 208 | (fc :pointer) 209 | (fc_data :pointer) 210 | (tol :pointer)) 211 | 212 | (export 'remove_equality_constraints) 213 | (cffi:defcfun ("nlopt_remove_equality_constraints" remove_equality_constraints) nlopt_result 214 | (opt :pointer)) 215 | 216 | (export 'add_equality_constraint) 217 | (cffi:defcfun ("nlopt_add_equality_constraint" add_equality_constraint) nlopt_result 218 | (opt :pointer) 219 | (h :pointer) 220 | (h_data :pointer) 221 | (tol :double)) 222 | 223 | (export 'add_precond_equality_constraint) 224 | (cffi:defcfun ("nlopt_add_precond_equality_constraint" add_precond_equality_constraint) nlopt_result 225 | (opt :pointer) 226 | (h :pointer) 227 | (pre :pointer) 228 | (h_data :pointer) 229 | (tol :double)) 230 | 231 | (export 'add_equality_mconstraint) 232 | (cffi:defcfun ("nlopt_add_equality_mconstraint" add_equality_mconstraint) nlopt_result 233 | (opt :pointer) 234 | (m :unsigned-int) 235 | (h :pointer) 236 | (h_data :pointer) 237 | (tol :pointer)) 238 | 239 | (export 'set_stopval) 240 | (cffi:defcfun ("nlopt_set_stopval" set_stopval) nlopt_result 241 | (opt :pointer) 242 | (stopval :double)) 243 | 244 | (export 'get_stopval) 245 | (cffi:defcfun ("nlopt_get_stopval" get_stopval) :double 246 | (opt :pointer)) 247 | 248 | (export 'set_ftol_rel) 249 | (cffi:defcfun ("nlopt_set_ftol_rel" set_ftol_rel) nlopt_result 250 | (opt :pointer) 251 | (tol :double)) 252 | 253 | (export 'get_ftol_rel) 254 | (cffi:defcfun ("nlopt_get_ftol_rel" get_ftol_rel) :double 255 | (opt :pointer)) 256 | 257 | (export 'set_ftol_abs) 258 | (cffi:defcfun ("nlopt_set_ftol_abs" set_ftol_abs) nlopt_result 259 | (opt :pointer) 260 | (tol :double)) 261 | 262 | (export 'get_ftol_abs) 263 | (cffi:defcfun ("nlopt_get_ftol_abs" get_ftol_abs) :double 264 | (opt :pointer)) 265 | 266 | (export 'set_xtol_rel) 267 | (cffi:defcfun ("nlopt_set_xtol_rel" set_xtol_rel) nlopt_result 268 | (opt :pointer) 269 | (tol :double)) 270 | 271 | (export 'get_xtol_rel) 272 | (cffi:defcfun ("nlopt_get_xtol_rel" get_xtol_rel) :double 273 | (opt :pointer)) 274 | 275 | (export 'set_x_weights) 276 | (cffi:defcfun ("nlopt_set_x_weights" set_x_weights) nlopt_result 277 | (opt :pointer) 278 | (w :pointer)) 279 | 280 | (export 'set_x_weights1) 281 | (cffi:defcfun ("nlopt_set_x_weights1" set_x_weights1) nlopt_result 282 | (opt :pointer) 283 | (w :double)) 284 | 285 | (export 'get_x_weights) 286 | (cffi:defcfun ("nlopt_get_x_weights" get_x_weights) nlopt_result 287 | (opt :pointer) 288 | (w :pointer)) 289 | 290 | 291 | (export 'set_xtol_abs1) 292 | (cffi:defcfun ("nlopt_set_xtol_abs1" set_xtol_abs1) nlopt_result 293 | (opt :pointer) 294 | (tol :double)) 295 | 296 | (export 'set_xtol_abs) 297 | (cffi:defcfun ("nlopt_set_xtol_abs" set_xtol_abs) nlopt_result 298 | (opt :pointer) 299 | (tol :pointer)) 300 | 301 | (export 'get_xtol_abs) 302 | (cffi:defcfun ("nlopt_get_xtol_abs" get_xtol_abs) nlopt_result 303 | (opt :pointer) 304 | (tol :pointer)) 305 | 306 | (export 'set_maxeval) 307 | (cffi:defcfun ("nlopt_set_maxeval" set_maxeval) nlopt_result 308 | (opt :pointer) 309 | (maxeval :int)) 310 | 311 | (export 'get_maxeval) 312 | (cffi:defcfun ("nlopt_get_maxeval" get_maxeval) :int 313 | (opt :pointer)) 314 | 315 | (export 'set_maxtime) 316 | (cffi:defcfun ("nlopt_set_maxtime" set_maxtime) nlopt_result 317 | (opt :pointer) 318 | (maxtime :double)) 319 | 320 | (export 'get_maxtime) 321 | (cffi:defcfun ("nlopt_get_maxtime" get_maxtime) :double 322 | (opt :pointer)) 323 | 324 | (export 'get_numevals) 325 | (cffi:defcfun ("nlopt_get_numevals" get_numevals) :double 326 | (opt :pointer)) 327 | 328 | (export 'force_stop) 329 | (cffi:defcfun ("nlopt_force_stop" force_stop) nlopt_result 330 | (opt :pointer)) 331 | 332 | (export 'set_force_stop) 333 | (cffi:defcfun ("nlopt_set_force_stop" set_force_stop) nlopt_result 334 | (opt :pointer) 335 | (val :int)) 336 | 337 | (export 'get_force_stop) 338 | (cffi:defcfun ("nlopt_get_force_stop" get_force_stop) :int 339 | (opt :pointer)) 340 | 341 | (export 'set_local_optimizer) 342 | (cffi:defcfun ("nlopt_set_local_optimizer" set_local_optimizer) nlopt_result 343 | (opt :pointer) 344 | (local_opt :pointer)) 345 | 346 | (export 'set_population) 347 | (cffi:defcfun ("nlopt_set_population" set_population) nlopt_result 348 | (opt :pointer) 349 | (pop :unsigned-int)) 350 | 351 | (export 'get_population) 352 | (cffi:defcfun ("nlopt_get_population" get_population) :unsigned-int 353 | (opt :pointer)) 354 | 355 | (export 'set_vector_storage) 356 | (cffi:defcfun ("nlopt_set_vector_storage" set_vector_storage) nlopt_result 357 | (opt :pointer) 358 | (dim :unsigned-int)) 359 | 360 | (export 'get_vector_storage) 361 | (cffi:defcfun ("nlopt_get_vector_storage" get_vector_storage) :unsigned-int 362 | (opt :pointer)) 363 | 364 | (export 'set_default_initial_step) 365 | (cffi:defcfun ("nlopt_set_default_initial_step" set_default_initial_step) nlopt_result 366 | (opt :pointer) 367 | (x :pointer)) 368 | 369 | (export 'set_initial_step) 370 | (cffi:defcfun ("nlopt_set_initial_step" set_initial_step) nlopt_result 371 | (opt :pointer) 372 | (dx :pointer)) 373 | 374 | (export 'set_initial_step1) 375 | (cffi:defcfun ("nlopt_set_initial_step1" set_initial_step1) nlopt_result 376 | (opt :pointer) 377 | (dx :double)) 378 | 379 | (export 'get_initial_step) 380 | (cffi:defcfun ("nlopt_get_initial_step" get_initial_step) nlopt_result 381 | (opt :pointer) 382 | (x :pointer) 383 | (dx :pointer)) 384 | 385 | (export 'set_munge) 386 | (cffi:defcfun ("nlopt_set_munge" set_munge) :void 387 | (opt :pointer) 388 | (munge_on_destroy :pointer) 389 | (munge_on_copy :pointer)) 390 | 391 | (export 'munge_data) 392 | (cffi:defcfun ("nlopt_munge_data" munge_data) :void 393 | (opt :pointer) 394 | (munge :pointer) 395 | (data :pointer)) 396 | 397 | (export 'minimize) 398 | (cffi:defcfun ("nlopt_minimize" minimize) nlopt_result 399 | (algorithm nlopt_algorithm) 400 | (n :int) 401 | (f :pointer) 402 | (f_data :pointer) 403 | (lb :pointer) 404 | (ub :pointer) 405 | (x :pointer) 406 | (minf :pointer) 407 | (minf_max :double) 408 | (ftol_rel :double) 409 | (ftol_abs :double) 410 | (xtol_rel :double) 411 | (xtol_abs :pointer) 412 | (maxeval :int) 413 | (maxtime :double)) 414 | 415 | (export 'minimize_constrained) 416 | (cffi:defcfun ("nlopt_minimize_constrained" minimize_constrained) nlopt_result 417 | (algorithm nlopt_algorithm) 418 | (n :int) 419 | (f :pointer) 420 | (f_data :pointer) 421 | (m :int) 422 | (fc :pointer) 423 | (fc_data :pointer) 424 | (fc_datum_size :pointer) 425 | (lb :pointer) 426 | (ub :pointer) 427 | (x :pointer) 428 | (minf :pointer) 429 | (minf_max :double) 430 | (ftol_rel :double) 431 | (ftol_abs :double) 432 | (xtol_rel :double) 433 | (xtol_abs :pointer) 434 | (maxeval :int) 435 | (maxtime :double)) 436 | 437 | (export 'minimize_econstrained) 438 | (cffi:defcfun ("nlopt_minimize_econstrained" minimize_econstrained) nlopt_result 439 | (algorithm nlopt_algorithm) 440 | (n :int) 441 | (f :pointer) 442 | (f_data :pointer) 443 | (m :int) 444 | (fc :pointer) 445 | (fc_data :pointer) 446 | (fc_datum_size :pointer) 447 | (p :int) 448 | (h :pointer) 449 | (h_data :pointer) 450 | (h_datum_size :pointer) 451 | (lb :pointer) 452 | (ub :pointer) 453 | (x :pointer) 454 | (minf :pointer) 455 | (minf_max :double) 456 | (ftol_rel :double) 457 | (ftol_abs :double) 458 | (xtol_rel :double) 459 | (xtol_abs :pointer) 460 | (htol_rel :double) 461 | (htol_abs :double) 462 | (maxeval :int) 463 | (maxtime :double)) 464 | 465 | (export 'get_local_search_algorithm) 466 | (cffi:defcfun ("nlopt_get_local_search_algorithm" get_local_search_algorithm) :void 467 | (deriv :pointer) 468 | (nonderiv :pointer) 469 | (maxeval :pointer)) 470 | 471 | (export 'set_local_search_algorithm) 472 | (cffi:defcfun ("nlopt_set_local_search_algorithm" set_local_search_algorithm) :void 473 | (deriv nlopt_algorithm) 474 | (nonderiv nlopt_algorithm) 475 | (maxeval :int)) 476 | 477 | (export 'nlopt_get_stochastic_population) 478 | (cffi:defcfun ("nlopt_get_stochastic_population" nlopt_get_stochastic_population) :int) 479 | 480 | 481 | (export 'nlopt_set_stochastic_population) 482 | (cffi:defcfun ("nlopt_set_stochastic_population" nlopt_set_stochastic_population) :void 483 | (pop :int)) 484 | 485 | ;;; 486 | ;;;;;;;;;; TEST 487 | ;;; 488 | 489 | 490 | ;; (defvar *counts* 0) 491 | 492 | ;; (cffi:defcallback myfunc :double ((n :unsigned-int) (x :pointer) (grad :pointer) (my_func_data :pointer)) 493 | ;; (incf *counts*) 494 | ;; (let ((sqrtx1 (sqrt (cffi:mem-aref x :double 1)))) 495 | ;; ;; Set objective gradient when it isn't null 496 | ;; (print (list (cffi:mem-aref x :double 0) (cffi:mem-aref x :double 1)) ) 497 | ;; (when (not (cffi:null-pointer-p grad)) 498 | ;; (setf (cffi:mem-aref grad :double 0) 0.0d0 499 | ;; (cffi:mem-aref grad :double 1) (/ 0.5d0 sqrtx1))) 500 | ;; ;; Return objective function value 501 | ;; sqrtx1 502 | ;; 1.0d0)) 503 | 504 | ;; (cffi:defcstruct my_constraint_data 505 | ;; (a :double) 506 | ;; (b :double)) 507 | 508 | ;; (cffi:defcallback myconstraint :double ((n :unsigned-int) (x :pointer) (grad :pointer) (data :pointer)) 509 | ;; (cffi:with-foreign-slots ((a b) data (:struct my_constraint_data)) 510 | ;; (print "conste") 511 | ;; (let ((x0 (cffi:mem-aref x :double 0)) 512 | ;; (x1 (cffi:mem-aref x :double 1))) 513 | ;; ;; Set constraint gradient when it isn't null 514 | ;; (when (not (cffi:null-pointer-p grad)) 515 | ;; (setf (cffi:mem-aref grad :double 0) (* 3 a (expt (+ (* a x0) b) 2)) 516 | ;; (cffi:mem-aref grad :double 1) -1d0)) 517 | ;; ;; Return constraint value 518 | ;; (print (- (expt (+ (* a x0) b) 3) x1))))) 519 | 520 | 521 | 522 | ;; (defun test (&optional (alg :NLOPT_LD_MMA)) 523 | ;; (let ((opt (nlopt_create (cffi:foreign-enum-value 'nlopt_algorithm alg) 2)) 524 | ;; (data-type '(:struct my_constraint_data))) 525 | ;; (cffi:with-foreign-objects ((lb :double 2) 526 | ;; (data0 data-type) 527 | ;; (data1 data-type) 528 | ;; (x :double 2) 529 | ;; (minf :double)) 530 | ;; (setf (cffi:mem-aref lb :double 0) -110d0) 531 | ;; (setf (cffi:mem-aref lb :double 1) 0.001d0) 532 | ;; (nlopt_set_lower_bounds opt lb) 533 | 534 | ;; (nlopt_set_min_objective opt (cffi:get-callback 'myfunc) (cffi:null-pointer)) 535 | ;; (cffi:with-foreign-slots ((a b) data0 (:struct my_constraint_data)) 536 | ;; (setf a 2d0 b 0d0)) 537 | ;; (cffi:with-foreign-slots ((a b) data1 (:struct my_constraint_data)) 538 | ;; (setf a -1d0 b 1d0)) 539 | 540 | ;; (nlopt_add_equality_constraint opt (cffi:get-callback 'myconstraint) data0 1d-2) 541 | ;; (nlopt_add_equality_constraint opt (cffi:get-callback 'myconstraint) data1 1d-2) 542 | ;; (nlopt_set_xtol_rel opt 1d-4) 543 | ;; (setf (cffi:mem-aref x :double 0) 1.234d0 544 | ;; (cffi:mem-aref x :double 1) 5.678d0) 545 | ;; (setf *counts* 0) 546 | ;; (print "optimizing") 547 | ;; (nlopt_optimize opt x minf) 548 | ;; (format t "found minimum in ~a steps~&" *counts*) 549 | ;; (format t "found minimum at (f ~a ~a) = ~a~&" (cffi:mem-aref x :double 0) (cffi:mem-aref x :double 1) (cffi:mem-ref minf :double)) 550 | ;; (nlopt_destroy opt)))) 551 | -------------------------------------------------------------------------------- /nlopt.lisp: -------------------------------------------------------------------------------- 1 | ;;;; nlopt.lisp 2 | 3 | (in-package #:nlopt) 4 | 5 | ;;; Library Loading 6 | (cffi:define-foreign-library nlopt 7 | (:windows "libnlopt.dll") 8 | (:linux "libnlopt.so")) 9 | 10 | ; Library file may be copied to project directory 11 | (pushnew (asdf:system-source-directory :nlopt) cffi:*foreign-library-directories*) 12 | (cffi:load-foreign-library 'nlopt) 13 | 14 | ;;; nlopt object 15 | (defclass nlopt () 16 | ((ptr :initarg :ptr :accessor ptr 17 | :documentation "Pointer to nlopt object") 18 | (dimension :initarg :dimension :reader dimension 19 | :type integer :initform 0 20 | :documentation "Number of variables") 21 | (objective :reader objective 22 | :documentation "Objective function") 23 | (callbacks :accessor callbacks :initform nil 24 | :documentation "Callbacks for different constraints") 25 | (preconditioner :reader preconditioner 26 | :documentation "Preconditioner used with `CCSAQ' algorithm") 27 | (identifiers :accessor identifiers :initform nil 28 | :documentation "Actually the nlopt c library is passed a single callback which 29 | selects which lisp callback to use. The identifer foreign struct is used to select/identify callbacks"))) 30 | 31 | ;;;;; 32 | ;;; Mechanism for callbacks 33 | ;;;;; 34 | 35 | (defparameter *nlopt-instance* nil 36 | "This variable is bound to the nlopt instance being called") 37 | 38 | (cffi:defcstruct callback-identifier 39 | (n :int)) 40 | 41 | (defun add-new-callback (nlopt function) 42 | "Adds a callback to nlopt object and returns an struct to identify that callback" 43 | (with-slots (callbacks identifiers) nlopt 44 | (let ((identifier (cffi:foreign-alloc '(:struct callback-identifier)))) 45 | (setf (cffi:foreign-slot-value identifier '(:struct callback-identifier) 'n) 46 | (length callbacks)) 47 | (setf callbacks (nconc callbacks (list function))) 48 | (setf identifiers (nconc identifiers (list identifier))) 49 | identifier))) 50 | 51 | (cffi:defcallback objective-callback :double 52 | ((n :unsigned-int) (x :pointer) (grad :pointer) (user_data :pointer)) 53 | "Callback function for objective" 54 | (declare (ignore n user_data)) 55 | (funcall (objective *nlopt-instance*) 56 | x 57 | (unless (cffi:null-pointer-p grad) 58 | grad) 59 | *nlopt-instance*)) 60 | 61 | (cffi:defcallback preconditioner-callback :double 62 | ((n :unsigned-int) (x :pointer) (v :pointer) (vpre :pointer) (user_data :pointer)) 63 | "Callback function for objective" 64 | (declare (ignore user_data)) 65 | (let ((r (funcall (preconditioner *nlopt-instance*) 66 | x 67 | v 68 | *nlopt-instance*))) 69 | (assert (= (length r) n)) 70 | (setf-doubles2 vpre r))) 71 | 72 | 73 | (cffi:defcallback constraint-callback :double 74 | ((dimension :unsigned-int) (x :pointer) (grad :pointer) (data :pointer)) 75 | "Callback function for constraints" 76 | (declare (ignore dimension)) 77 | (cffi:with-foreign-slots ((n) data (:struct callback-identifier)) 78 | (funcall (nth n (callbacks *nlopt-instance*)) 79 | x 80 | (unless (cffi:null-pointer-p grad) 81 | grad) 82 | *nlopt-instance*))) 83 | 84 | (cffi:defcallback mconstraint-callback :void 85 | ((m :unsigned-int) (result :pointer) (dimension :unsigned-int) (x :pointer) (grad :pointer) (data :pointer)) 86 | "Callback function for mconstraints (multiple constraints)" 87 | (declare (ignore dimension)) 88 | (cffi:with-foreign-slots ((n) data (:struct callback-identifier)) 89 | (let ((r (funcall (nth n (callbacks *nlopt-instance*)) 90 | x 91 | (unless (cffi:null-pointer-p grad) 92 | grad) 93 | *nlopt-instance*))) 94 | (assert (= (length r) m)) 95 | (setf-doubles2 result r)))) 96 | 97 | ;;;;; 98 | ;;; Bindings 99 | ;;;;; 100 | 101 | (defun algorithms () 102 | "List of algorithms available" 103 | (cffi:foreign-enum-keyword-list 'c:nlopt_algorithm)) 104 | 105 | (defun algorithm (nlopt) 106 | "Get algorithm used; Returns a keyword" 107 | (c:get_algorithm (ptr nlopt))) 108 | 109 | (defun algorithm-name (algorithm) 110 | "Human readable name of `algorithm'" 111 | (c:algorithm_name algorithm)) 112 | 113 | (defun create (algorithm dimension) 114 | "Create an Non-linear optimization object object 115 | `algorithm' is one of the `(algorithms)' 116 | `dimension' is number of parameters in the optimization problem" 117 | (assert (and (integerp dimension) 118 | (> dimension 0)) 119 | (dimension)) 120 | (assert (member algorithm (algorithms)) (algorithm)) 121 | (let ((ptr (c:create (cffi:foreign-enum-value 'c:nlopt_algorithm algorithm) dimension))) 122 | (unless (cffi:null-pointer-p ptr) 123 | (let ((nlopt (make-instance 'nlopt 124 | :dimension dimension 125 | :ptr ptr))) 126 | (prog1 nlopt 127 | (tg:finalize nlopt 128 | #'(lambda () 129 | (c:destroy ptr)))))))) 130 | 131 | (defmethod copy-object ((obj nlopt)) 132 | "Make of copy of nlopt object in lisp side only 133 | You might want to use `copy' to make actual copy of object in lisp and c side" 134 | (let ((o (make-instance 'nlopt 135 | :dimension (dimension obj)))) 136 | (with-slots (objective callbacks identifiers) obj 137 | (setf (slot-value o 'objective) objective 138 | (callbacks o) callbacks 139 | (slot-value o 'identifiers) identifiers)) 140 | o)) 141 | 142 | (defun copy (nlopt) 143 | "Make a copy of `nlopt' problem 144 | If you have subclassed the `nlopt' object define a `copy-object' method on your subclass 145 | that copies all slots (including those of `nlopt')" 146 | (let* ((foreign-new (c:copy (ptr nlopt))) 147 | (lisp-new (copy-object nlopt))) 148 | (setf (ptr lisp-new) foreign-new) 149 | (tg:finalize lisp-new 150 | #'(lambda () 151 | (c:destroy foreign-new))) 152 | lisp-new)) 153 | 154 | ;;;;; Setting and Gettting Upper and Lower *Bounds* for parameters 155 | 156 | (defun (setf lower-bounds) (bounds nlopt) 157 | "Set lower bounds for parameters 158 | bounds can be a number, list or array of doubles" 159 | (etypecase bounds 160 | (number (c:set_lower_bounds1 (ptr nlopt) bounds)) 161 | (list (assert (= (length bounds) (dimension nlopt))) 162 | (cffi:with-pointer-to-vector-data (ptr (doubles bounds)) 163 | (c:set_lower_bounds (ptr nlopt) ptr))) 164 | (doubles (assert (= (length bounds) (dimension nlopt))) 165 | (cffi:with-pointer-to-vector-data (ptr bounds) 166 | (c:set_lower_bounds (ptr nlopt) ptr))))) 167 | 168 | (defun (setf upper-bounds) (bounds nlopt) 169 | "Set upper bounds for parameters 170 | bounds can be a number, list or array of doubles" 171 | (etypecase bounds 172 | (number (c:set_upper_bounds1 (ptr nlopt) bounds)) 173 | (list (assert (= (length bounds) (dimension nlopt))) 174 | (cffi:with-pointer-to-vector-data (ptr (doubles bounds)) 175 | (c:set_upper_bounds (ptr nlopt) ptr))) 176 | (doubles (assert (= (length bounds) (dimension nlopt))) 177 | (cffi:with-pointer-to-vector-data (ptr bounds) 178 | (c:set_upper_bounds (ptr nlopt) ptr))))) 179 | 180 | (defun lower-bounds (nlopt) 181 | "Get lower bounds for parameters" 182 | (let ((lb (make-array (the integer (dimension nlopt)) :element-type 'double-float))) 183 | (cffi:with-pointer-to-vector-data (lb-ptr lb) 184 | (c:get_lower_bounds (ptr nlopt) lb-ptr)) 185 | lb)) 186 | 187 | (defun upper-bounds (nlopt) 188 | "Get upper bounds for parameters" 189 | (let ((ub (make-array (dimension nlopt) :element-type 'double-float))) 190 | (cffi:with-pointer-to-vector-data (ub-ptr ub) 191 | (c:get_lower_bounds (ptr nlopt) ub-ptr)) 192 | ub)) 193 | 194 | (defun (setf lower-bound) (bound nlopt i) 195 | (c:set_lower_bound (ptr nlopt) i (coerce bound 'double-float))) 196 | 197 | (defun lower-bound (nlopt i) 198 | (aref (lower-bounds nlopt) i)) 199 | 200 | (defun (setf upper-bound) (bound nlopt i) 201 | (c:set_upper_bound (ptr nlopt) i (coerce bound 'double-float))) 202 | 203 | (defun upper-bound (nlopt i) 204 | (aref (upper-bounds nlopt) i)) 205 | 206 | ;;;;; Set objective function 207 | 208 | (defun set-min-objective (nlopt function) 209 | "Set minimization objective function where 210 | function(pointer to doubles x, 211 | pointer to doubles grad or NULL, 212 | nlopt) 213 | returns a double-float" 214 | (c:set_min_objective (ptr nlopt) (cffi:get-callback 'objective-callback) (cffi:null-pointer)) 215 | (setf (slot-value nlopt 'objective) function)) 216 | 217 | (defun set-max-objective (nlopt function) 218 | "Set maximazation objective function where 219 | function(pointer to doubles x, 220 | pointer to doubles grad or NULL, 221 | nlopt) 222 | returns a double-float" 223 | (c:set_max_objective (ptr nlopt) (cffi:get-callback 'objective-callback) (cffi:null-pointer)) 224 | (setf (slot-value nlopt 'objective) function)) 225 | 226 | (defun set-precond-min-objective (nlopt function preconditioner) 227 | "If you know the Hessian (second-derivative) matrix of your objective function, 228 | i.e. the matrix H with Hij=∂2f/∂x_i∂x_j 229 | 230 | for an objective f, then in principle this could be used to accelerate local 231 | optimization. In fact, even a reasonable approximation for H could be useful if 232 | it captures information about the largest eigenvalues of H and the corresponding 233 | eigenvectors. Such an approximate Hessian is often called a preconditioner in 234 | the context of iterative solvers, so we adopt that terminology here. 235 | 236 | Currently, support for preconditioners in NLopt is somewhat experimental, and is 237 | only used in the NLOPT_LD_CCSAQ algorithm. 238 | 239 | The preconditioner is a function 240 | 241 | pre(pointer to doubles x, 242 | pointer to doubles v, 243 | nlopt) 244 | 245 | This function should take a vector v and should compute vpre = H(x) v where H is 246 | an approximate second derivative at x. The CCSAQ algorithm requires that your 247 | matrix H be positive semidefinite, i.e. that it be real-symmetric with 248 | nonnegative eigenvalues." 249 | (c:set_precond_min_objective (ptr nlopt) (cffi:get-callback 'objective-function) 250 | (cffi:get-callback 'preconditioner-callback) 251 | (cffi:null-pointer)) 252 | (setf (slot-value nlopt 'objective) function 253 | (slot-value nlopt 'preconditioner) preconditioner)) 254 | 255 | (defun set-precond-max-objective (nlopt function preconditioner) 256 | "See documentation for `(set-precond-min-objective)'" 257 | (c:set_precond_max_objective (ptr nlopt) (cffi:get-callback 'objective-function) 258 | (cffi:get-callback 'preconditioner-callback) 259 | (cffi:null-pointer)) 260 | (setf (slot-value nlopt 'objective) function 261 | (slot-value nlopt 'preconditioner) preconditioner)) 262 | 263 | 264 | ;;;;; Add Constraints 265 | 266 | (defun add-equality-constraint (nlopt function &optional (tol 1d-6)) 267 | "Add an equality constaint c(x) = 0 268 | c(pointer to doubles x, pointer to gradient or NULL, nlopt) 269 | tolerance `tol' is used to check -tol <= c(x) <= tol" 270 | (let ((callback-identifier (add-new-callback nlopt function))) 271 | (ensure-success 272 | (c:add_equality_constraint (ptr nlopt) 273 | (cffi:get-callback 'constraint-callback) 274 | callback-identifier 275 | tol)))) 276 | 277 | 278 | 279 | (defun add-inequality-constraint (nlopt function &optional (tol 1d-6)) 280 | "Add an inequality constaint c(x) <= 0 281 | c(pointer to doubles x, pointer to gradient or NULL, nlopt) 282 | tolerance `tol' is used to check c(x) <= tol" 283 | (let ((callback-identifier (add-new-callback nlopt function))) 284 | (ensure-success 285 | (c:add_inequality_constraint (ptr nlopt) 286 | (cffi:get-callback 'constraint-callback) 287 | callback-identifier 288 | tol)))) 289 | 290 | 291 | (defun remove-equality-constraints (nlopt) 292 | "Remove all equality constraints" 293 | ;; TODO: remove identifiers, and callbacks from nlopt object too 294 | (c:remove_equality_constraints (ptr nlopt))) 295 | 296 | (defun remove-inequality-constraints (nlopt) 297 | "Remove all inequality constraints" 298 | ;; TODO: remove identifiers, and callbacks from nlopt object too 299 | (c:remove_inequality_constraints (ptr nlopt))) 300 | 301 | (defun add-equality-mconstraint (nlopt m function tol) 302 | "Add multiple equality constraints c_i(x) = 0; i=1,2,..m 303 | `function' = `c' should return list of `m' doubles 304 | c(pointer to doubles x, 305 | pointer to gradient(jacobian) `∂c_i(x)/∂x_j' or NULL, (m rows, n columns) 306 | nlopt) 307 | `tol' is tolerances as in single constaints, it can be a number, nil, list of tolerance or array of double-floats 308 | 309 | In some applications with multiple constraints, it is more convenient to define a single function 310 | that returns the values (and gradients) of all constraints at once. For example, different constraint 311 | functions might share computations in some way. Or, if you have a large number of constraints, you may 312 | wish to compute them in parallel." 313 | (let ((callback-identifier (add-new-callback nlopt function)) 314 | (tol (etypecase tol 315 | (number (doubles-array* m tol)) 316 | (null (cffi:null-pointer)) 317 | (list (assert (= (length tol) m)) (doubles tol)) 318 | (doubles tol)))) 319 | (with-vector-ptr-to tol 320 | (ensure-success 321 | (c:add_equality_mconstraint (ptr nlopt) 322 | m 323 | (cffi:get-callback 'mconstraint-callback) 324 | callback-identifier 325 | tol))))) 326 | 327 | (defmethod add-inequality-mconstraint (nlopt m function tol) 328 | "Add multiple inequality constraints c_i(x) = 0; i=1,2,..m 329 | `function' = `c' should return list of `m' doubles 330 | c(m, 331 | pointer to doubles x, 332 | pointer to gradient(jacobian) `∂c_i(x)/∂x_j', (m rows, n columns) 333 | nlopt) 334 | `tol' is tolerances as in single constaints, it can be a number, nil, list of tolerance or array of double-floats 335 | 336 | In some applications with multiple constraints, it is more convenient to define a single function 337 | that returns the values (and gradients) of all constraints at once. For example, different constraint 338 | functions might share computations in some way. Or, if you have a large number of constraints, you may 339 | wish to compute them in parallel." 340 | (let ((callback-identifier (add-new-callback nlopt function)) 341 | (tol (etypecase tol 342 | (number (doubles-array m tol)) 343 | (null (cffi:null-pointer)) 344 | (list (assert (= (length tol) m)) (doubles tol)) 345 | (doubles tol)))) 346 | (ensure-success 347 | (c:add_inequality_mconstraint (ptr nlopt) 348 | m 349 | (cffi:get-callback 'mconstraint-callback) 350 | callback-identifier 351 | tol)))) 352 | 353 | ;;;;; Stopping Criteria 354 | 355 | ;;; Objective function stopvalue 356 | (defun (setf stopval) (stopval nlopt) 357 | "Stop when an objective value of at least stopval is found: 358 | stop minimizing when an objective value <= stopval is found, 359 | or stop maximizing a value >= stopval is found." 360 | (c:set_stopval (ptr nlopt) stopval)) 361 | 362 | (defun stopval (nlopt) 363 | "Get the current stopping value for objective function" 364 | (c:get_stopval (ptr nlopt))) 365 | 366 | ;;; Objective function update tolerances 367 | (defun (setf ftol-rel) (tol nlopt) 368 | "Set relative tolerance on function value: stop when an optimization step 369 | (or an estimate of the optimum) changes the objective function value by 370 | less than `tol' multiplied by the absolute value of the function value. 371 | (If there is any chance that your optimum function value is close to zero, 372 | you might want to set an absolute tolerance with (setf (ftol-abs nlopt)) as well.) 373 | 374 | Criterion is disabled if `tol' is non-positive." 375 | (declare (type double-float tol)) 376 | (c:set_ftol_rel (ptr nlopt) tol)) 377 | 378 | (defun ftol-rel (nlopt) 379 | "Get relative tolerance in changes in objective function value" 380 | (c:get_ftol_rel (ptr nlopt))) 381 | 382 | (defun (setf ftol-abs) (tol nlopt) 383 | "Set relative tolerance on function value: stop when an optimization step 384 | (or an estimate of the optimum) changes the objective function value by 385 | less than `tol' multiplied by the absolute value of the function value. 386 | 387 | Criterion is disabled if `tol' is non-positive" 388 | (declare (type double-float tol)) 389 | (c:set_ftol_abs (ptr nlopt) tol)) 390 | 391 | ;;; Parameter update tolerances 392 | (defun (setf xtol-rel) (tol nlopt) 393 | "Set relative tolerance on optimization parameters: stop when an optimization step 394 | (or an estimate of the optimum) causes a relative change the parameters `x' by less than `tol', 395 | i.e. ∥Δx∥_w