-
Notifications
You must be signed in to change notification settings - Fork 33
Open
Description
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
Labels
No labels