Tutorial 15: A loss network

A loss network models a system in which an arriving job (a call or connection) is admitted only if enough resources are free; otherwise it is blocked and lost rather than queued. Such models arise in circuit-switched telephony and in multirate broadband networks, where each class of call requires a fixed number of circuits on each link along its route.

In LINE a loss network is expressed as an open model whose stations sit inside a finite capacity region (FCR) with the DROP policy: when the region is full, arriving jobs are dropped. The stationary distribution is of product form, and the quantities of interest are the per-class blocking probabilities and the normalization constant g(C). Here two classes of calls share an infinite-server Delay station. Class 1 offers load 0.3 and class 2 offers 0.2 (arrival rate over service rate). The region admits at most 5 calls in total and at most 3 of each class.

Loss Network Diagram
model = Network('LossNetwork');
% Block 1: nodes
source = Source(model, 'Source');
delay  = Delay(model, 'Delay');
sink   = Sink(model, 'Sink');
% Block 2: classes
class1 = OpenClass(model, 'Class1');
class2 = OpenClass(model, 'Class2');
source.setArrival(class1, Exp(0.3));
source.setArrival(class2, Exp(0.2));
delay.setService(class1, Exp(1.0));
delay.setService(class2, Exp(0.8));
% Block 3: topology
P = model.initRoutingMatrix();
P.set(class1, class1, source, delay, 1.0);
P.set(class1, class1, delay, sink, 1.0);
P.set(class2, class2, source, delay, 1.0);
P.set(class2, class2, delay, sink, 1.0);
model.link(P);
% Block 4: finite capacity region with dropping
fcr = model.addRegion({delay});
fcr.setGlobalMaxJobs(5);
fcr.setClassMaxJobs(class1, 3);
fcr.setClassMaxJobs(class2, 3);
fcr.setDropRule(class1, true);
fcr.setDropRule(class2, true);
% Block 5: solution
% Erlang fixed-point (reduced-load) approximation, the default
AvgTable = SolverNC(model).avgTable()
% Monte Carlo summation (Ross-Wang): also estimates the normalizing constant
ncmci = SolverNC(model, 'method', 'mci', 'samples', 1e5, 'seed', 23000);
AvgTableMCI = ncmci.avgTable()
lG = ncmci.result.Prob.logNormConstAggr
% Simulation cross-check: JMT natively supports DROP finite capacity regions
AvgTableJMT = SolverJMT(model, 'seed', 23000, 'samples', 1e5).avgTable()
Network model = new Network("LossNetwork");
// Block 1: nodes
Source source = new Source(model, "Source");
Delay delay = new Delay(model, "Delay");
Sink sink = new Sink(model, "Sink");
// Block 2: classes
OpenClass class1 = new OpenClass(model, "Class1", 0);
OpenClass class2 = new OpenClass(model, "Class2", 0);
source.setArrival(class1, new Exp(0.3));
source.setArrival(class2, new Exp(0.2));
delay.setService(class1, new Exp(1.0));
delay.setService(class2, new Exp(0.8));
// Block 3: topology
RoutingMatrix P = model.initRoutingMatrix();
P.set(class1, class1, source, delay, 1.0);
P.set(class1, class1, delay, sink, 1.0);
P.set(class2, class2, source, delay, 1.0);
P.set(class2, class2, delay, sink, 1.0);
model.link(P);
// Block 4: finite capacity region with dropping
model.addRegion(Collections.singletonList(delay));
Region fcr = model.getRegions().get(0);
fcr.setGlobalMaxJobs(5);
fcr.setClassMaxJobs(class1, 3);
fcr.setClassMaxJobs(class2, 3);
fcr.setDropRule(class1, true);
fcr.setDropRule(class2, true);
// Block 5: solution
// Erlang fixed-point (reduced-load) approximation, the default
new SolverNC(model).avgTable().print();
// Monte Carlo summation (Ross-Wang): also estimates the normalizing constant
SolverNC ncMci = new SolverNC(model, "method", "mci");
ncMci.options.samples = 100000;
ncMci.options.seed = 23000;
ncMci.avgTable().print();
// Simulation cross-check: JMT natively supports DROP finite capacity regions
SolverJMT jmt = new SolverJMT(model, "seed", 23000);
jmt.options.samples = 100000;
jmt.avgTable().print();
val model = Network("LossNetwork")
// Block 1: nodes
val source = Source(model, "Source")
val delay = Delay(model, "Delay")
val sink = Sink(model, "Sink")
// Block 2: classes
val class1 = OpenClass(model, "Class1", 0)
val class2 = OpenClass(model, "Class2", 0)
source.setArrival(class1, Exp(0.3))
source.setArrival(class2, Exp(0.2))
delay.setService(class1, Exp(1.0))
delay.setService(class2, Exp(0.8))
// Block 3: topology
val P = model.initRoutingMatrix()
P.set(class1, class1, source, delay, 1.0)
P.set(class1, class1, delay, sink, 1.0)
P.set(class2, class2, source, delay, 1.0)
P.set(class2, class2, delay, sink, 1.0)
model.link(P)
// Block 4: finite capacity region with dropping
model.addRegion(listOf(delay))
val fcr = model.getRegions().get(0)
fcr.setGlobalMaxJobs(5)
fcr.setClassMaxJobs(class1, 3)
fcr.setClassMaxJobs(class2, 3)
fcr.setDropRule(class1, true)
fcr.setDropRule(class2, true)
// Block 5: solution
SolverNC(model).avgTable().print()
val ncMci = SolverNC(model, "method", "mci")
ncMci.options.samples = 100000
ncMci.options.seed = 23000
ncMci.avgTable().print()
SolverJMT(model, "seed", 23000).avgTable().print()
from line_solver import *

model = Network('LossNetwork')
# Block 1: nodes
source = Source(model, 'Source')
delay = Delay(model, 'Delay')
sink = Sink(model, 'Sink')
# Block 2: classes
class1 = OpenClass(model, 'Class1')
class2 = OpenClass(model, 'Class2')
source.set_arrival(class1, Exp(0.3))
source.set_arrival(class2, Exp(0.2))
delay.set_service(class1, Exp(1.0))
delay.set_service(class2, Exp(0.8))
# Block 3: topology
P = model.init_routing_matrix()
P.set(class1, class1, source, delay, 1.0)
P.set(class1, class1, delay, sink, 1.0)
P.set(class2, class2, source, delay, 1.0)
P.set(class2, class2, delay, sink, 1.0)
model.link(P)
# Block 4: finite capacity region with dropping
fcr = model.add_region(delay)
fcr.set_global_max_jobs(5)
fcr.set_class_max_jobs(class1, 3)
fcr.set_class_max_jobs(class2, 3)
fcr.set_drop_rule(class1, True)
fcr.set_drop_rule(class2, True)
# Block 5: solution
# Erlang fixed-point (reduced-load) approximation, the default
print(SolverNC(model).avg_table())
# Monte Carlo summation (Ross-Wang): also estimates the normalizing constant
print(SolverNC(model, method='mci', samples=100000, seed=23000).avg_table())
# Simulation cross-check: JMT natively supports DROP finite capacity regions
print(SolverJMT(model, seed=23000, samples=100000).avg_table())

Expected Output

SolverNC recognizes the single-Delay DROP region as a loss network and offers two methods: the default Erlang fixed-point (reduced-load) approximation and the Monte Carlo summation (Ross-Wang), which also estimates the log-normalization constant log g(C). All three solutions agree closely, confirming the product-form result against simulation:

AvgTable =                          % SolverNC, erlangfp (default)
    Station    JobClass     QLen       Util      RespT    ResidT     ArvR       Tput
     Delay      Class1     0.29895    0.29895       1         1     0.29895    0.29895
     Delay      Class2     0.24969    0.24969    1.25      1.25     0.19975    0.19975
AvgTableMCI =                       % SolverNC, mci (Ross-Wang)
     Delay      Class1     0.29901    0.29901       1         1     0.29901    0.29901
     Delay      Class2     0.24967    0.24967    1.25      1.25     0.19973    0.19973
lG = 0.4994                         % log-normalization constant log g(C)
AvgTableJMT =                       % SolverJMT simulation
     Delay      Class1     0.29976    0.29976    0.99627    0.99627    0.29886    0.29824
     Delay      Class2     0.25189    0.25189     1.2535     1.2535    0.20144    0.20144