;;; math.lisp -- various numerical operations
;;
;; Time-stamp: <2004-01-01 emarsden>
;;
;; some basic mathematical benchmarks


(in-package :cl-bench.math)


(defun factorial (n)
  (declare (type integer n))
  (if (zerop n) 1
      (* n (factorial (1- n)))))

(defun run-factorial ()
  (declare (inline factorial))
  (factorial 500))

(defun fib (n)
  (declare (type integer n))
  (if (< n 2) 1 (+ (fib (- n 1)) (fib (- n 2)))))

(defun run-fib ()
  (declare (inline fib))
  (fib 25))

(defun fib-ratio (n)
  (declare (type integer n))
  (labels ((fr (n)
             (if (= n 1) 1
                 (1+ (/ (fr (- n 1)))))))
    (numerator (fr n))))

(defun run-fib-ratio ()
  (declare (inline fib-ratio))
   (fib-ratio 150))


;; The Ackermann function is the simplest example of a well-defined total
;; function which is computable but not primitive recursive, providing a
;; counterexample to the belief in the early 1900s that every computable
;; function was also primitive recursive (Dtzel 1991). It grows faster
;; than an exponential function, or even a multiple exponential function. 
(defun ackermann (m n)
  (declare (type integer m n))
  (cond
    ((zerop m) (1+ n))
    ((zerop n) (ackermann (1- m) 1))
    (t (ackermann (1- m) (ackermann m (1- n))))))

(defun run-ackermann ()
   (ackermann 3 11))


(defun mset-level/complex (c)
  (declare (type complex c))
  (loop :for z = #c(0 0) :then (+ (* z z) c)
        :for iter :from 1 :to 300
        :until (> (abs z) 4.0)
        :finally (return iter)))

(defun mset-level/dfloat (c1 c2)
  (declare (type double-float c1 c2))
  (let ((z1 0.0d0)
        (z2 0.0d0)
        (aux 0.0d0))
    (do ((iter 0 (1+ iter)))
        ((or (> (abs (+ (* z1 z1) (* z2 z2))) 4.0)
             (> iter 300))
         iter)
      (setq aux z1
            z1 (+ (* z1 z1) (- (* z2 z2)) c1)
            z2 (+ (* 2.0d0 z2 aux) c2)))))

(defun run-mandelbrot/complex ()
  (let ((n 100)
        (sum 0.0))
    (dotimes (i n)
      (incf sum (mset-level/complex (complex 0.0001d0 (/ i n 0.25d0)))))))

(defun run-mandelbrot/dfloat ()
  (let ((n 100)
        (sum 0.0))
    (dotimes (i n)
      (incf sum (mset-level/dfloat 0.0001d0 (/ i n 0.25d0))))))



;; Common Lisp implementation of the multiple recursive random number
;; generator (MRG) of l'Ecuyer. Written by Raymond Toy. 

(eval-when (:compile-toplevel :load-toplevel)
  (defconstant +m1+   4294967087d0)
  (defconstant +m2+   4294944443d0)
  (defconstant +a12+     1403580d0)
  (defconstant +a13n+     810728d0)
  (defconstant +a21+      527612d0)
  (defconstant +a23n+    1370589d0)
  (defconstant +norm+ (/ (1+ +m1+))))

(declaim (inline mrg32k3a-comp-1 mrg32k3a-comp-2))

(defun mrg32k3a-comp-1 (state)
  (declare (type (simple-array double-float (6)) state)
	   (optimize (speed 3) (safety 0)))
  (let ((s10 (aref state 0))
	(s11 (aref state 1)))
    (declare (type (double-float 0d0 4294967086d0) s10 s11))
    (let* ((p1 (- (* s11 +a12+) (* s10 +a13n+)))
	   (k (ftruncate (/ p1 +m1+)))
	   (p1b (- p1 (* k +m1+)))
	   (p1c (if (< p1b 0)
		    (+ p1b +m1+)
		    p1b)))
      (shiftf (aref state 0)
	      (aref state 1)
	      (aref state 2)
	      p1c)
      p1c)))

(defun mrg32k3a-comp-2 (state)
  (declare (type (simple-array double-float (6)) state)
	   (optimize (speed 3) (safety 0)))
  (let ((s20 (aref state 3))
	(s22 (aref state 5)))
    (declare (type (double-float 0d0 4294944442d0) s20 s22))
    (let* ((p2 (- (* s22 +a21+) (* s20 +a23n+)))
	   (k (ftruncate (/ p2 +m2+)))
	   (p2b (- p2 (* k +m2+)))
	   (p2c (if (< p2b 0)
		    (+ p2b +m2+)
		    p2b)))
      (shiftf (aref state 3)
	      (aref state 4)
	      (aref state 5)
	      p2c)
      p2c)))

(declaim (inline mrg32k3a))

(defun mrg32k3a (state)
  (declare (type (simple-array double-float (6)) state)
	   (optimize (speed 3) (safety 0)))
  (let ((p1 (mrg32k3a-comp-1 state))
	(p2 (mrg32k3a-comp-2 state)))
    (if (<= p1 p2)
	(* (+ (- p1 p2) +m1+) +norm+)
	(* (- p1 p2) +norm+))))

(defun gen-mrg32 (n state)
  (declare (fixnum n)
           (optimize (speed 3) (safety 0)))
  (let ((y 0d0))
    (dotimes (k n)
      (declare (fixnum k))
      (setf y (mrg32k3a state)))
    (* 3 y)))

(defun gen-ran (n)
  (declare (fixnum n)
           (optimize (speed 3) (safety 0)))
  (let ((y 0d0))
    (dotimes (k n)
      (declare (fixnum k))
      (setf y (random 1d0)))
    (* 3 y)))

(defun run-mrg32k3a ()
  (declare (inline gen-ran))
  (gen-ran 1000000))

;; EOF
