;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; This file is part of ICCLE2. ; ; ICCLE2 is free software: you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation, either version 3 of the License, or ; (at your option) any later version. ; ; ICCLE2 is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with ICCLE2. If not, see . ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;

Random Modeling Tricks

;

Note: this code uses these structs. ;

The Base Trick

;

Base trick: remember to use my random number generators and ;to use (reset-seed) to reset before continuing. ;

The Simplest Trick

;

Shuffle a list.

(defun shuffle (l)
  (dotimes (i (length l) l)
    (rotatef
     (elt l i)
     (elt l (my-random-int (length l))))))
;
;

Random Sort

;

If two items are the same, return any one at random.

(defun <~ (n1 n2)
  (if (= n1 n2)
      (< (my-randone) 0.5)
      (< n1 n2)))
;

Can be used to, say, randomly reorder a cons list and ;if two cons keys are the same, return any at random.

(deftest test<~ ()
  (reset-seed)
  (let* ((data '((20 . orange)
		 (10 . tim)		
		 (10 . tam)
		 ( 5 . apple)
		 (10 . tom)))
	 (sorted-data  (sort (copy-list data) 
			     #'<~ :key #'first)))
    (print sorted-data)
    (check (equalp sorted-data
		   '((5 . APPLE) (10 . TIM) (10 . TOM) 
		     (10 . TAM) (20 . ORANGE))))))
;

Build a Space of Options

;

Standard proptocol

;

When we add a new item to a range, ; declare the range is no longer ready.

(defun range+ (x n)
  (setf (range-ready?   x) nil)
  (range++ x n)
  n)
;
;

If a range is not ready, call range-range!! (to make it ready) then ;delcare the range ready.

(defun range-ready! (x)
  (unless (range-ready? x)
    (range-ready!! x)
    (setf (range-ready? x) t))
  x)
;

Adding New Items

;

Adding an item to a range of min..max.

(defmethod range++ ((x range) n)
  (setf (range-max    x) (max (range-max x) n)
        (range-min    x) (min (range-min x) n)))
;

Adding an item to a distribution.

(defmethod range++ ((x dist) n)
  (let ((key (funcall (dist-key   x) n))
        (val (funcall (dist-value x) n)))
    (setf (dist-max    x) (max (dist-max x) key)
          (dist-min    x) (min (dist-min x) key))
    (incf (dist-sum x) key)
    (push n (dist-all x))))
;

Adding an item to a gaussian.

(defmethod range++ ((x gaussian) n)
  (incf (gaussian-n     x))
  (incf (gaussian-sum   x) n)
  (incf (gaussian-sumsq x) (* n n)))
;

Making a Range Ready

;

Some ranges can be made ready, very easy.

(defmethod range-ready!! ((x range)) t)
;

To make a dist ready, sort the numbers.

(defmethod range-ready!! ((x dist))
  (setf (dist-all x) 
        (sort (dist-all x) #'> :key (dist-key x))))
;

To make a gaussian ready, recompute the ;mean and standard deviation.

(defmethod range-ready!! ((x gaussian))
  (let* ((n     (gaussian-n x))
         (sum   (gaussian-sum x))
         (sumsq (gaussian-sumsq x)))
    (setf (gaussian-stdev x)  (stdev n sum sumSq)
          (gaussian-mean x)   (mean n sum))))
;

Select From a Space of Options

;

Select Any from a List

;

Select any item from a list

(defmethod any ((x list))
  (nth (my-random-int (length x)) x))
;

Select Any From Hash

(defmethod any ((x hash-table))
  (let ((count (hash-table-count x)))
    (unless (zerop count)
      (let  ((n (1+ (my-random-int count))))
        (dohash (key value x)
          (if (<= (decf n) 0)
              (return-from any value)))))))
;

For example...

(deftest test-any-hash ()
  (reset-seed)
  (let ((h (make-hash-table)))
    (mapc #'(lambda (k v)
	      (setf (gethash k h) v))
	  '(who what when)
	  '(tim lecturer 2009))
    (check (= 2009 (any h)))))
;

Select Any from a Range

(defmethod any ((x range))
  (range-ready! x)
  (let ((max (range-min x))
        (min (range-max x)))
    (if (> min max)
        (+ max (my-random (+ 1 (- min max))))
        (+ min (my-random (+ 1 (- max min)))))))
;

For example...

(defun test-ranges (how)
  (reset-seed)
  (let ((x (funcall how)))
    (dolist (n '(1  20 54 13 13 3 1 3 2 1245 1 412))
      (range+ x n))
    (any x)))

(deftest testing-any-range ()
  (check 
    (= 1148 
       (floor (test-ranges #'make-range)))))
;

Select Any from a Gaussian

(defmethod any ((x gaussian))
  (range-ready! x)
  (normal (gaussian-mean x) (gaussian-stdev x)))
;

For example...

(deftest test-gaussian ()
  (check
    (= 345
       (floor (test-ranges #'make-gaussian)))))
;

Select Any from a Dist

(defmethod any ((x dist))
  (range-ready! x)
  (labels ((val  (y) (funcall (dist-value x) y))
           (key  (y) (funcall (dist-key   x) y)))
    (let* ((r   (my-random (dist-sum x)))
           (n   (dist-sum  x))
           (all (dist-all x))
           (out (val (first all))))
      (dolist (one (rest all) out)
        (decf n (key one))
        (if (<= n r)
            (return-from any out))
        (setf out (val one))))))
;

For example...

(deftest test-dists ()
  (reset-seed)
  (let (out
        (d (make-dist))
        (values '(a b c d e f g h i j k l m 
                  n o p q r s t u v w x y z)))
    (doitems (one n values)
      (range+  d (cons n one))) ; e.g. (cons 3 'c)
    (dotimes (i 100)
      (push (any d) out)) 
    (check
      (equalp (sort out #'string>)
             '(Z Z Z Z Z Z Z Z Z Y Y Y Y Y Y Y X X X X 
               W W W W W W W W V V V V V V U U U U T T 
               T T T T T T S S S S S S S S S R R R Q Q
               Q Q Q P P P P P P O O O O O N N L K K K 
               K J J J J I H G G G F E E D A A A A A A)))))
;