examples/jackson.ss
#lang scheme/base
;;; Jackson Network from PySim

(require (planet williams/simulation/simulation-with-graphics))
(require (planet williams/science/random-distributions))

;;; Parameters

(define n 3)
(define m #(1.0 2.0 1.0))
(define p (vector
           (make-discrete #(0.0 0.5 0.5 0.0))
           (make-discrete #(0.0 0.0 0.8 0.2))
           (make-discrete #(0.2 0.0 0.0 0.8))))
(define np '(1 1 1))
(define mu (/ 1.0 1.5))
(define max-messages 10000)

;;; Global Variables (set in main)

(define n-arrivals 0)
(define n-in-system #f)
(define time-in-system #f)
(define processor #f)

;;; Data Collection

(define-process (message i)
  (let ((arrive-time (current-simulation-time))
        (work-duration 0.0))
    (set-variable-value!
     n-in-system (+ (variable-value n-in-system) 1))
    (let loop ((node 0))               ; start node is always 0
      (when (< node n)
        (with-resource ((vector-ref processor node))
          (work (random-exponential (vector-ref m node))))
        (loop (random-discrete (vector-ref p node)))))
    (set-variable-value!
     n-in-system (- (variable-value n-in-system) 1))
    (set-variable-value!
     time-in-system (- (current-simulation-time)
                       arrive-time))))

(define (generator)
  (do ((i 0 (+ i 1)))
      ((= i max-messages) (void))
    (set! n-arrivals (+ n-arrivals 1))
    (schedule now (message i))
    (wait (random-exponential (/ mu)))))

(define (main)
  (with-new-simulation-environment
    ;; Initialize global variables
    (set! n-arrivals 0)
    (set! n-in-system (make-variable 0))
    (accumulate (variable-history n-in-system))
    (set! time-in-system (make-variable))
    (tally (variable-statistics time-in-system))
    (set! processor (list->vector
                     (map make-resource np)))
    ;;
    (schedule (at 0.0) (generator))
    (schedule (at 5000.0) (stop-simulation))
    (start-simulation)
    (printf "Mean number in system = ~a~n" (variable-mean n-in-system))
    (printf "Mean delay in system  = ~a~n" (variable-mean time-in-system))
    (printf "Total time run        = ~a~n" (current-simulation-time))
    (printf "Total jobs arrived    = ~a~n" n-arrivals)
    (printf "Total jobs completed  = ~a~n" (variable-n time-in-system))
    (printf "Average arrival rate  = ~a~n" (/ n-arrivals
                                              (current-simulation-time)))
    (write-special (history-plot (variable-history n-in-system)))
    (newline)))

(main)