ggq 0.1.1

A simulation framework for multi-server queues.
Documentation
use crate::customer::Customer;
use crate::event::{Event, EventType};
use crate::server::{Server, ServerStatus};
use crate::simulation::{
    observation::Observation, params::SimParams, service_metrics::ServiceMetrics,
};
use rand::prelude::*;
use rand_distr::Exp;
use std::cmp::Reverse;
use std::collections::BinaryHeap;

pub struct SimEnv {
    event_queue: BinaryHeap<Event>,
    customers: BinaryHeap<Customer>,
    t: f64,
    params: SimParams,
    server: Server,
    queue: BinaryHeap<Reverse<Customer>>,
    pub history: Vec<Observation>,
    service_metrics: ServiceMetrics,
    n_served: usize,
}

impl SimEnv {
    pub fn new(params: &SimParams) -> SimEnv {
        let sim = SimEnv {
            event_queue: BinaryHeap::new(),
            customers: BinaryHeap::new(),
            t: 0.0,
            params: *params,
            server: Server {
                status: ServerStatus::Idling,
            },
            queue: BinaryHeap::new(),
            history: Vec::new(),
            service_metrics: ServiceMetrics::new(),
            n_served: 0 as usize,
        };

        sim
    }

    pub fn simulate(&mut self, until: f64) {
        let first_arrival_time = self.t
            + Exp::new(1.0 / self.params.mean_inter_arrival_time)
                .unwrap()
                .sample(&mut thread_rng());
        let service_time = Exp::new(1.0 / self.params.mean_service_time)
            .unwrap()
            .sample(&mut thread_rng());
        let c = Customer::new(first_arrival_time, service_time);
        self.customers.push(c);

        let e = Event::new(EventType::Arrival, c, first_arrival_time);
        self.event_queue.push(e);
        self.t = first_arrival_time;

        while self.t < until {
            let n_in_service = match self.server.status {
                ServerStatus::Idling => 0 as usize,
                ServerStatus::Busy => 1 as usize,
            };
            let obs = Observation {
                t: self.t,
                n_in_queue: self.queue.len(),
                n_in_system: self.queue.len() + n_in_service,
            };
            self.history.push(obs);
            let next_event = self.event_queue.pop();
            match next_event {
                None => {
                    // println!("No event in queue. returning");
                    return;
                }
                Some(mut e) => {
                    // println!("{:4.4} {e}", self.t);
                    match e.event_type {
                        EventType::Arrival => {
                            self.handle_arrival(&e);
                        }
                        EventType::StartService => {
                            self.handle_start_service(&mut e);
                        }
                        EventType::Departure => {
                            self.handle_end_service(&mut e);
                        }
                    };
                    self.t = e.t;
                }
            }
        }
    }

    fn handle_arrival(&mut self, event: &Event) {
        match self.server.status {
            ServerStatus::Busy => {
                self.queue.push(Reverse(event.get_customer()));
            }
            ServerStatus::Idling => {
                let start_event =
                    Event::new(EventType::StartService, event.get_customer(), event.t);
                self.event_queue.push(start_event);
            }
        }
        let next_inter_arrival_time = Exp::new(1.0 / self.params.mean_inter_arrival_time)
            .unwrap()
            .sample(&mut thread_rng());
        let next_service_time = Exp::new(1.0 / self.params.mean_service_time)
            .unwrap()
            .sample(&mut thread_rng());
        let new_customer = Customer::new(
            event.get_customer().arrival_time + next_inter_arrival_time,
            next_service_time,
        );
        self.event_queue.push(Event::new(
            EventType::Arrival,
            new_customer,
            new_customer.arrival_time,
        ))
    }

    fn handle_start_service(&mut self, event: &mut Event) {
        let t = event.t;
        event.get_customer_mut().set_service_start(t);

        let end_event = Event::new(
            EventType::Departure,
            event.get_customer(),
            t + event.get_customer().service_time,
        );
        self.event_queue.push(end_event);
        self.server.status = ServerStatus::Busy;
    }

    fn handle_end_service(&mut self, event: &mut Event) {
        let t = event.t;
        let served_customer = event.get_customer_mut();
        served_customer.set_service_end(t);

        let w_q = served_customer.waiting_time().unwrap();
        let w_s = served_customer.cycle_time().unwrap();

        match (
            self.service_metrics.mean_waiting_time,
            self.service_metrics.mean_cycle_time,
        ) {
            (None, None) => {
                self.service_metrics.mean_cycle_time = Some(w_s);
                self.service_metrics.mean_waiting_time = Some(w_q);
            }
            _ => {
                self.service_metrics.mean_waiting_time = Some(
                    (self.service_metrics.mean_waiting_time.unwrap() * self.n_served as f64 + w_q)
                        / (self.n_served as f64 + 1.0),
                );
                self.service_metrics.mean_cycle_time = Some(
                    (self.service_metrics.mean_cycle_time.unwrap() * self.n_served as f64 + w_s)
                        / (self.n_served as f64 + 1.0),
                );
            }
        }
        self.n_served += 1;

        let next_customer = self.queue.pop();
        self.server.status = ServerStatus::Idling;
        match next_customer {
            Some(c) => {
                let e = Event::new(EventType::StartService, c.0, event.t);
                self.event_queue.push(e);
            }
            None => {}
        }
    }

    pub fn get_metrics(&self) -> ServiceMetrics {
        self.service_metrics
    }
}