Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nloptimize macro expands to different code than example resulting in division by zero error. #1

Open
dylanjm opened this issue Jun 19, 2023 · 0 comments

Comments

@dylanjm
Copy link

dylanjm commented Jun 19, 2023

Hello, I'm new to using common lisp and have been playing with your fantastic library. I've been running into errors when trying to run some of the examples provided in your repo.

Here is some relevant info:

OS: macOS Ventura 13.4
SBCL: 2.3.4
NLOPT: 2.7.1 (installed via homebrew on macOS)

I had to make a minor addition to your code to allow nlopt to recognize my libnlopt.dylib file on my Mac.

;;; Library Loading
(cffi:define-foreign-library nlopt
  (:windows "libnlopt.dll")
  (:linux "libnlopt.so")
  (:darwin "libnlopt.dylib"))

On to the issue at hand. When I run the following example, I get the following error:

(nlopt:nloptimize ((x y)
                   :initial '(1.234 5.678))
  (:minimize (sqrt y))
  (:satisfy (>= y (expt (* 2 x) 3))
            (>= y (expt (- 1 x) 3))
            (> y 0))))
arithmetic error DIVISION-BY-ZERO signalled
   [Condition of type DIVISION-BY-ZERO]

So when I run macroexpand on the above code example, I get the following output:

(LET ((*NLOPT-INSTANCE* (CREATE :NLOPT_LN_COBYLA 2)))
  (SET-MIN-OBJECTIVE *NLOPT-INSTANCE*
                     (LAMBDA (#:X417 #:GRAD418 #:NLOPT419)
                       (DECLARE (IGNORE #:GRAD418 #:NLOPT419))
                       (LET ((Y (DREF #:X417 1)))
                         (SQRT Y))))
  (PROGN
   (ADD-INEQUALITY-CONSTRAINT *NLOPT-INSTANCE*
                              (LAMBDA (#:X420 #:GRAD421 #:NLOPT422)
                                (DECLARE (IGNORE #:GRAD421 #:NLOPT422))
                                (LET ((Y (DREF #:X420 1)) (X (DREF #:X420 0)))
                                  (- (EXPT (* 2 X) 3) Y))))
   (ADD-INEQUALITY-CONSTRAINT *NLOPT-INSTANCE*
                              (LAMBDA (#:X423 #:GRAD424 #:NLOPT425)
                                (DECLARE (IGNORE #:GRAD424 #:NLOPT425))
                                (LET ((Y (DREF #:X423 1)) (X (DREF #:X423 0)))
                                  (- (EXPT (- 1 X) 3) Y))))
   (SETF (LOWER-BOUND *NLOPT-INSTANCE* 1) 0))
  (OPTIMIZE-NLOPT *NLOPT-INSTANCE* (DOUBLES* '(1.234 5.678))))

Now you can see that this code is slightly different than the code provided in example.lisp under the example-mma function definition:

(defun example-mma()
  "The https://nlopt.readthedocs.io/en/latest/NLopt_Tutorial/ problem
minimize sqrt(y)
subject to
  y >= (2x)^3
  y >= (1 - x)^3
  y>0"
  (let ((nlopt (create :nlopt_ld_mma 2)))
    (setf (lower-bound nlopt 1) 0d0)
    (set-min-objective nlopt (lambda (x grad nlopt)
                               (declare (ignore nlopt))
                               (let ((sqrtx1 (sqrt (dref x 1))))
                                 (when grad
                                   (setf-doubles grad
                                                 0.0d0
                                                 (/ 0.5d0 sqrtx1)))
                                 sqrtx1)))
    (add-inequality-constraint nlopt
                               (lambda (x grad nlopt)
                                 (declare (ignore nlopt))
                                 (let ((x0 (dref x 0))
                                       (x1 (dref x 1)))
                                   (setf-doubles grad
                                                 (* 6 (expt (* 2 x0) 2))
                                                 -1d0)
                                   (- (expt (* 2 x0) 3) x1)))
                               1d-2)
    (add-inequality-constraint nlopt
                               (lambda (x grad nlopt)
                                 (declare (ignore nlopt))
                                 (let ((x0 (dref x 0))
                                       (x1 (dref x 1)))
                                   (setf-doubles grad
                                                 (* -3 (expt (+ (- x0) 1d0) 2))
                                                 -1d0)
                                   (- (expt (+ (- x0) 1) 3) x1)))
                               1d-2)
    (setf (xtol-rel nlopt) 1d-4)
    (optimize-nlopt nlopt (doubles (list 1.234d0 5.678d0)))))

When I run (example-mma) I get the following output:

#(0.3333333342139688d0 0.29629628951338166d0)
0.5443310477213124d0 (54.43310477213124d0%)
:NLOPT_XTOL_REACHED

I'm not advanced enough in lisp to understand fully why it's erroring out, but I do notice that it appears the chosen algorithm is different between the two (:nlopt_ln_cobyla vs. :nlopt_ld_mma) and also the macro expanded code leaves out the when conditional found in the objective function in (example-mma)

Please let me know if you might have a work around or way to address this issue. Thank you for your time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant