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

Real variables are not bound #31

Open
swapneils opened this issue Jun 13, 2023 · 2 comments
Open

Real variables are not bound #31

swapneils opened this issue Jun 13, 2023 · 2 comments

Comments

@swapneils
Copy link

In all my test cases, real variables converge to a range-size of 0 (and have equivalent upper and lower bounds when printed) but still aren't actually bound to a value, leading to a (fail) condition.

Test case (using ratios to avoid some issues with CL float arithmetic that lead to (fail) results):

(let ((v (a-real-betweenv -10 10))
      (a 1/10)
      (b 23/10))
  (assert! (=v a (-v b v)))
  (one-value (solution v
                       (static-ordering #'divide-and-conquer-force))))
;; => (fail)

There's a quickfix where we manually check range-size in restrict-bounds! and setf variable-value if it's 0, but I assume this issue is produced by a noticer not working correctly on reals, and I don't yet understand Screamer's noticer system enough to pinpoint the problem.

Quickfix:

(in-package :screamer)
(defun restrict-bounds! (x lower-bound upper-bound)
  ;; note: X must be a variable.
  ;; note: LOWER-BOUND and UPPER-BOUND must be real constants.
  (when (variable-integer? x)
    (if lower-bound (setf lower-bound (ceiling lower-bound)))
    (if upper-bound (setf upper-bound (floor upper-bound))))
  (if (or (eq (variable-value x) x) (not (variable? (variable-value x))))
      (let ((run? nil))
        (when (and lower-bound
                   (or (not (variable-lower-bound x))
                       (> lower-bound (variable-lower-bound x))))
          (when (and (variable-upper-bound x)
                   (< (variable-upper-bound x) lower-bound))
              (fail))
          (when (or (not (variable-lower-bound x))
                    (not (variable-upper-bound x))
                    (>= (/ (- lower-bound (variable-lower-bound x))
                           (- (variable-upper-bound x) (variable-lower-bound x)))
                        *minimum-shrink-ratio*))
            (local (setf (variable-lower-bound x) lower-bound))
            (setf run? t)))
        (when (and upper-bound
                   (or (not (variable-upper-bound x))
                       (< upper-bound (variable-upper-bound x))))
          (when (and (variable-lower-bound x)
                   (> (variable-lower-bound x) upper-bound))
            (fail))
          (when (or (not (variable-lower-bound x))
                    (not (variable-upper-bound x))
                    (>= (/ (- (variable-upper-bound x) upper-bound)
                           (- (variable-upper-bound x) (variable-lower-bound x)))
                        *minimum-shrink-ratio*))
            (local (setf (variable-upper-bound x) upper-bound))
            (setf run? t)))
        (when run?
          (cond ((eq (variable-enumerated-domain x) t)
                 (if (and (variable-lower-bound x)
                          (variable-upper-bound x)
                          (variable-integer? x)
                          (or (null *maximum-discretization-range*)
                              (<= (- (variable-upper-bound x)
                                     (variable-lower-bound x))
                                  *maximum-discretization-range*)))
                     (set-enumerated-domain!
                      x (integers-between
                         (variable-lower-bound x)
                         (variable-upper-bound x)))))
                ((or (and lower-bound
                          (some #'(lambda (element) (< element lower-bound))
                                (variable-enumerated-domain x)))
                     (and upper-bound
                          (some #'(lambda (element) (> element upper-bound))
                                (variable-enumerated-domain x))))
                 ;; note: Could do less consing if had LOCAL DELETE-IF.
                 ;;       This would also allow checking list only once.
                 (set-enumerated-domain!
                  x (remove-if #'(lambda (element)
                                   (or (and lower-bound (< element lower-bound))
                                       (and upper-bound (> element upper-bound))))
                               (variable-enumerated-domain x)))))


          ;; When the range-size of x is 0, set (variable-value x)
          (let ((range (range-size x)))
            (when (and range
                       (zerop range))
              (setf (variable-value x) (variable-lower-bound x))))


          (run-noticers x)))))

;; Test
(let ((v (a-real-betweenv -10 10))
      (a 1/10)
      (b 23/10))
  (assert! (=v a (-v b v)))
  (one-value (solution v
                       (static-ordering #'divide-and-conquer-force))))
;; => 11/5 (2.2)
@nikodemus
Copy link
Owner

Hi, just letting you know that I'm not actively maintaining Screamer these days. If someone wants to pick it up and run, they should feel free to do so.

@rpgoldman
Copy link

@nikodemus Maybe move this into sharplispers and see if someone will take it over?

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

3 participants