Tutorial 2: Multiclass M/G/1 Queue

This example considers a more challenging variant with two classes of incoming jobs with non-exponential service times. For the first class, service times are Erlang distributed; for the second class, they are read from a trace file. Both classes have exponentially distributed inter-arrival times.

Multiclass M/G/1 Queue Network Diagram
% Example 2: A multiclass M/G/1 queue
model = Network('M/G/1');
source = Source(model,'Source');
queue = Queue(model, 'Queue', SchedStrategy.FCFS);
sink = Sink(model,'Sink');

jobclass1 = OpenClass(model, 'Class1');
jobclass2 = OpenClass(model, 'Class2');

source.setArrival(jobclass1, Exp(0.5));
source.setArrival(jobclass2, Exp(0.5));

queue.setService(jobclass1, Erlang.fitMeanAndSCV(1,1/3));
queue.setService(jobclass2, Replayer(which('example_trace.txt')));

P = model.initRoutingMatrix();
P.set(jobclass1, Network.serialRouting(source,queue,sink));
P.set(jobclass2, Network.serialRouting(source,queue,sink));
model.link(P);

ldesAvgTable = LDES(model,'seed',23000,'samples',10000).avgTable()

queue.setService(jobclass2, Replayer(which('example_trace.txt')).fitAPH());
mamAvgTable = MAM(model).avgTable()
from line_solver import *

model = Network('M/G/1')
source = Source(model, 'Source')
queue = Queue(model, 'Queue', SchedStrategy.FCFS)
sink = Sink(model, 'Sink')

jobclass1 = OpenClass(model, 'Class1')
jobclass2 = OpenClass(model, 'Class2')

source.set_arrival(jobclass1, Exp(0.5))
source.set_arrival(jobclass2, Exp(0.5))

queue.set_service(jobclass1, Erlang.fit_mean_and_scv(1.0, 1/3))
queue.set_service(jobclass2, Replayer(lineRootFolder() +
    "/examples/gettingstarted/example_trace.txt").fit_aph())

P = model.init_routing_matrix()
P.set(jobclass1, Network.serial_routing(source,queue,sink))
P.set(jobclass2, Network.serial_routing(source,queue,sink))
model.link(P)

ldesAvgTable = LDES(model, seed=23000, samples=10000).avg_table()
mamAvgTable = MAM(model).avg_table()
import jline.examples.ExampleData;
import jline.lang.RoutingMatrix;
import jline.lang.processes.Erlang;
import jline.lang.processes.Replayer;
import jline.solvers.NetworkAvgTable;
import jline.solvers.ldes.LDES;
import jline.solvers.mam.MAM;

Network model = new Network("M/G/1");
Source source = new Source(model, "Source");
Queue queue = new Queue(model, "Queue", SchedStrategy.FCFS);
Sink sink = new Sink(model, "Sink");

OpenClass jobclass1 = new OpenClass(model, "Class1");
OpenClass jobclass2 = new OpenClass(model, "Class2");
source.setArrival(jobclass1, new Exp(0.5));
source.setArrival(jobclass2, new Exp(0.5));
queue.setService(jobclass1, Erlang.fitMeanAndSCV(1, (double) 1 / 3));
String fileName = ExampleData.path("/example_trace.txt");
queue.setService(jobclass2, new Replayer(fileName));

RoutingMatrix P = model.initRoutingMatrix();
P.set(jobclass1, jobclass1, Network.serialRouting(source, queue, sink));
P.set(jobclass2, jobclass2, Network.serialRouting(source, queue, sink));
model.link(P);

NetworkAvgTable ldesAvgTable = new LDES(model, "seed", 23000, "samples", 10000).avgTable();
ldesAvgTable.print();
queue.setService(jobclass2, new Replayer(fileName).fitAPH());
new MAM(model).avgTable().print();
#include "line/solvers/wrappers/ldes/solver_ldes.h"
#include "line/solvers/mam/solver_mam_runner.h"

Network model("M/G/1");
Source source(model, "Source");
Queue queue(model, "Queue", SchedStrategy::FCFS);
Sink sink(model, "Sink");

OpenClass jobclass1(model, "Class1");
OpenClass jobclass2(model, "Class2");
source.set_arrival(jobclass1, Exp(0.5));
source.set_arrival(jobclass2, Exp(0.5));
queue.set_service(jobclass1, Distrib<double>::erlang_fit(1.0, 1.0 / 3.0));
const std::vector<double> samples{/* values from example_trace.txt */};
queue.set_service(jobclass2, Replayer(samples));

Routing P;
for (std::size_t r : {jobclass1, jobclass2}) {
    P.set(r, r, source, queue, 1.0);
    P.set(r, r, queue, sink, 1.0);
}
model.link(P);

// Simulate the raw trace with the LDES client, then fit and solve with MAM.
ldes::LdesOptions sim;
sim.seed = 23000;
sim.samples = 10000;
const ldes::LdesResult sres = ldes::solver_ldes(model.get_struct(), sim);

mam::MamOptions opt;
const mva::AvgResult<double> res =
    mam::solver_mam_run_analyzer(model.get_struct(), opt);

Expected Output (LDES solver)

ldesAvgTable =
    Station    JobClass     QLen        Util       RespT     ResidT      ArvR       Tput
    _______    ________    _______    ________    _______    _______    _______    _______
    Source      Class1           0           0          0          0          0        0.5
    Source      Class2           0           0          0          0          0        0.5
    Queue       Class1     0.83114     0.48506     1.7003     1.7003     0.4891    0.48871
    Queue       Class2     0.41233    0.050177    0.83801    0.83801    0.49234    0.49165

Expected Output (MAM solver)

mamAvgTable =
    Station    JobClass     QLen        Util       RespT     ResidT     ArvR    Tput
    _______    ________    _______    ________    _______    _______    ____    ____
    Source      Class1           0           0          0          0      0     0.5
    Source      Class2           0           0          0          0      0     0.5
    Queue       Class1     0.87646         0.5     1.7529     1.7529    0.5     0.5
    Queue       Class2       0.427    0.050536    0.85399    0.85399    0.5     0.5