( This page is part of the NOVA system. )

nova/guess

Code to find and fix values from a range of possible values.

There are tools here to:

Note the following convention:

That is:

Files

nova/lisp/guess/guess-db.lisp
Stores the core data structure of the "guess" system.
nova/lisp/guess/guess.lisp
Source code for the "guess" system that defines how to guess from: There is also a generic interface to:

Example

(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

Guess-db.lisp

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"

)

Guess-db.lisp

Guessing from Anything

(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)))))

Guessing from Numerics

(defun ?quantity (min max)
  "Choose a number between min to max"
  (+ min (my-random (- max min))))

Guessing from Lists

(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))

Guessing from Structs

"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)))

Making guesses

(defun ? (key)
  "find one value for 'key' in *db*"
  (let ((range (geta key (db-settings *db*))))
    (guess range)))

Caching guesses

(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))

Zapping guesses

(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))