;;; Carlo C. Maley  11/17/94


;;; Note: this is fragile to trying to rerun a non-existant run file.

;;; Random number generator functions for SAGA.  It requires there to
;;; be a subdirectory called "input" which will contain the files
;;; "last_number.in" (with the number of the last run) and the a bunch
;;; of files of the form "run_#.saga" (which contain the run number #
;;; and then the random-state structure.

(in-package 'USER)


;;; This initializes a the random number generator.  If a number is
;;; supplied, it tries to rerun that trial by finding a file entitled
;;; run_#.init.  The last run number is saved in a file called
;;; "last_number.in"  If the argument to init-random is < 0, it reruns
;;; the last run.

(defvar *run-number* 0)

(defun init-random (&optional (run-number -1))
  (if (< run-number 0) 
      (let ((r-state (make-random-state t)))
	(setf *random-state* r-state)
	(write-random-state r-state (update-run-number)))
    (let ((r-state (read-random-state run-number)))
      (setf *run-number* run-number)
      (unless (null r-state) (setf *random-state* r-state)))))

(defun update-run-number ()
  (let ((n ()))
    (with-open-file (run-num-stream "input/last_number.in" :direction :input
				    :if-does-not-exist nil)
		    (unless (null run-num-stream)
			    (setf n (read run-num-stream nil))))
    (when (numberp n)
	  (progn
	    (with-open-file (run-num-stream "input/last_number.in" 
					    :direction :output)
			    (print (1+ n) run-num-stream))
	    (setf *run-number* (1+ n))))))


(defun write-random-state (r-state run-num)
  (with-open-file (rand-state-stream (get-file-name run-num)
				     :direction :output)
		  (print run-num rand-state-stream)
		  (print r-state rand-state-stream)))

(defun read-random-state (run-num)
  (with-open-file (rand-state-stream (get-file-name run-num)
				     :direction :input
				     :if-does-not-exist nil)
       (if (and (streamp rand-state-stream)
		  (= run-num (read rand-state-stream nil)))
	     (let ((r-state (read rand-state-stream nil)))
	       (if (random-state-p r-state) r-state nil))
	 (cond
	  ((null rand-state-stream)
	     (progn 
	       (format t "File: ~a doesn't exist.~%" (get-file-name run-num))
	       (format t "I'm creating a new run file.~%")
	       (let ((r-state (make-random-state t)))
		 (write-random-state r-state (update-run-number))
		 r-state)))
	  ((>= run-num 0) 
	   (format t "Contents of ~a don't match the run number ~a.~%"
		   (get-file-name run-num) run-num))
	  (t (let ((r-state (read rand-state-stream nil))) ;rerunning
	       (if (random-state-p r-state) r-state nil)))))))

			  
(defun get-file-name (n)
  (if (< n 0) 
      (concatenate 'string "input/run_" 
		   (princ-to-string 
		    (with-open-file (in-stream "input/last_number.in" 
					       :direction :input)
				    (read in-stream nil))) ".txt")
  (concatenate 'string "input/run_" (princ-to-string n) ".txt")))


(defun test (n)
  (if (= 0 n) (init-random)
    (init-random n))
  (format t "~a " (random 100))
  (format t "~a " (random 100))  
  (format t "~a " (random 100))  
  (format t "~a " (random 100))  
  (format t "~a " (random 100))  
  (format t "~a " (random 100))  
  (format t "~a " (random 100))  
  (format t "~a " (random 100))  
  (format t "~a " (random 100))  
  (format t "~a " (random 100))  
  (format t "~a " (random 100)))

(defun uniform ()
  (/ (random most-positive-fixnum)
     (* 1.0 most-positive-fixnum)))
