;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 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
Note: this code uses these structs. ;
Base trick: remember to use my random number generators and ;to use (reset-seed) to reset before continuing. ;
Shuffle a list.
(defun shuffle (l)
(dotimes (i (length l) l)
(rotatef
(elt l i)
(elt l (my-random-int (length l))))))
;
;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))))))
;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 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))) ;
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 any item from a list
(defmethod any ((x list)) (nth (my-random-int (length x)) x)) ;
(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)))))
;
(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)))))
;(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)))))
;
(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)))))
;