Code to find and fix values from a range of possible values.
There are tools here to:
Note the following convention:
That is:
(let ((db (make-db :settings `((a . ,(make-num :min 20 :max 40)) (b . ,(make-bag :range '(1 3 5 7 9))))))) (egs :guess0 (eg '(?quantity 10 20)) (eg '(?num (make-num :min 10 :max 20))) (eg '(?elt '(a b c d e))) (eg '(?bag (make-bag :range '(1 2 3 4)))) (eg `(guess0a ,db)) ))
The call to
(make-db :settings `((a . ,(make-num :min 20 :max 40)) (b . ,(make-bag :range '(1 3 5 7 9)))))
registers two variables "a" and "b" that are numeric ranges and a bag of lists, respectively. The following code shows queries to those variables. Note the call to (zaps) in between the calls. This zaps the cache, so the subsequent calls generate new values.
(defun guess0a (&optional (*db* *db*)) (zaps) (format t "~a ~a~%" (! 'a) (! 'a)) (zaps) (format t "~a ~a~%" (! 'a) (! 'a)) t )
The first three examples show simple guesses.
CL-USER> (demo :guess0) ;;;; 1) example ;IN: (?QUANTITY 10 20) ;GOT: 15.43989376883949d0 ;ok ;;;; 2) example ;IN: (?NUM (MAKE-NUM MIN 10 MAX 20)) ;GOT: 18.294572885285397d0 ;ok ;;;; 3) example ;IN: (?ELT '(A B C D E)) ;GOT: D ;ok ;;;; 4) example ;IN: (?BAG (MAKE-BAG RANGE '(1 2 3 4))) ;GOT: 1 ;ok
The fifth illustrates how calling (! 'a) twice returns the same value and, then, after the reset, returns a different value, twice.
;;;; 5) example ;IN: (GUESS0A) 35.62434469145925d0 35.62434469145925d0 38.36122935561521d0 38.36122935561521d0 ;GOT: T ;ok
Here's data structure for storing ranges. The current version of this code does not utilize all these slots (future planned work).
(defstruct (db (:print-function (lambda (x str d) (declare (ignore x d)) (format str "")))) defaults ; design time : space of all possibilities args ; call time : command-line settings from the users settings ; setup time : "args", modified by args ! ; stuff cached by the "!" function using "settings" )
(defun guess (range) "Central station of the 'guess' system. All guessable types have to be registered here." (case (type-of range) (one-a (?one-a range)) (one-b (?one-b range)) (bag (?bag range)) (num (?num range)) (sf (?sf range)) (dr (?dr range)) (em (?em range)) (otherwise (warn "can't handle ~a of type ~a" range (type-of range)))))
(defun ?quantity (min max) "Choose a number between min to max" (+ min (my-random (- max min))))
(defun ?elt (choices) "choose one item from a list of choices" (elt choices (floor (my-random (length choices)))))
(defun ?elts (choices n) "return up to n randomly selected choices" (if (zerop n) nil (let ((any (?elt choices))) (cons any (?elts (remove any choices) (- n 1))))))
(defun ?any (l &key (control 0.8) (power 1)) "Select any of items from list l, favoring smaller policies. If control is 0.9, then some items of lists of size 5 includes the whole list. " (let* ((factor (expt control power)) (r (?quantity 0 1)) (some (round (log r factor))) (enough (min (length l) (max 1 some)))) (?elts l enough)))
(defun ?lots (l) "Pull lots of things from a list." (?any l :power 1))
(defun ?some (l) "Pull some things from a list." (?any l :power 2))
(defun ?few (l) "Pull a few things from a list." (?any l :power 3))
"Thing" is a structure with two children "num" and "bag". The processing of sub-types of "num" and "bag" can be implemented using generic functions.
(defstruct thing) (defstruct (num (:include thing)) min max) (defstruct (bag (:include thing)) range)
Extract one item from a "bag".
(defun ?bag (x) "select one item from a range" (?elt (bag-range x)))
Extract one item from a "num".
(defmacro ?num (x) "select one item within a number min to max" `(?quantity (num-min ,x) (num-max ,x)))
(defun ? (key) "find one value for 'key' in *db*" (let ((range (geta key (db-settings *db*)))) (guess range)))
(defun ! (key) "find (or compute), then store a value for 'key' in *db*" (let ((value (cdr (assoc key (db-! *db*))))) (unless value (setf value (? key)) (push (cons key value) (db-! *db*))) value))
(defun zap (key) "zap key from the *db* cache" (setf (db-! *db*) (rassoc key (db-! *db*))))
(defun zaps () "zap all keys in the *db* cache" (setf (db-! *db*) nil))