Skip to content

Real variables are not bound #31

@swapneils

Description

@swapneils

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions