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