LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
infer_quick_model.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012-2026, QORE Lab, Imperial College London
3 * All rights reserved.
4 */
5#ifndef LINE_API_INFER_INFER_QUICK_MODEL_H
6#define LINE_API_INFER_INFER_QUICK_MODEL_H
7
8/**
9 * @file
10 * @ingroup api_infer
11 * Convenience factory for the single-layer networks the inference estimators fit.
12 *
13 * Port of matlab/src/api/infer/infer_quick_model.m and
14 * python/line_solver/inference/api/infer_quick_model.py.
15 *
16 * The model is named `quickModel` and has one Queue `QueueStation<i>` per entry
17 * of `stations`, with that discipline, `servers[i]` servers and infinite
18 * capacity, and one class `Class<c>` per row of `demands`, served at station i
19 * by `Exp.fitMean(demands(c,i))`.
20 *
21 * - OPEN: a Source `mySource` and a Sink `mySink`, every class routed serially
22 * Source -> QueueStation1 -> ... -> QueueStationM -> Sink. No arrival
23 * process is set, as in both references: the estimators supply it.
24 * - CLOSED: class c has `jobs[c]` jobs referenced at QueueStation1 and follows
25 * `routing[c]` (an M x M station-to-station matrix) when given, and the
26 * cycle 1 -> 2 -> ... -> M -> 1 otherwise. `routing` is ignored when open.
27 *
28 * The open branch follows the Python reference. The MATLAB open branch stored
29 * the Source in `node{1}` and then overwrote it with the first queue, so the
30 * serial path started at a queue and the Source was never routed.
31 */
32
33#include <cstddef>
34#include <limits>
35#include <string>
36#include <vector>
37
40#include "line/num/number.h"
41#include "line/util/error.h"
42#include "line/util/matrix.h"
43
44namespace line {
45namespace infer {
46
47/**
48 * @brief Build a simple open or closed queueing network.
49 *
50 * @param is_open true for an open network, false for a closed one
51 * @param stations (M) scheduling discipline of each queue
52 * @param demands (K x M) mean service demand of class c at station i
53 * @param servers (M) server count per station; empty means one each
54 * @param jobs (K) population per closed class; empty means one each
55 * @param routing (K) per-class M x M station routing for a closed model; empty means serial
56 * @return the linked network
57 */
58template <class T>
59qn::Network<T> infer_quick_model(bool is_open, const std::vector<lang::SchedStrategy>& stations,
60 const Matrix<T>& demands,
61 const std::vector<double>& servers = std::vector<double>(),
62 const std::vector<double>& jobs = std::vector<double>(),
63 const std::vector<Matrix<T>>& routing = std::vector<Matrix<T>>()) {
64 const std::size_t M = stations.size();
65 const std::size_t K = demands.rows();
66 if (M == 0) throw InputError("infer_quick_model: at least one station is required");
67 if (K == 0) throw InputError("infer_quick_model: at least one class is required");
68 if (demands.cols() != M)
69 throw InputError("infer_quick_model: demands must have one column per station");
70 if (!servers.empty() && servers.size() != M)
71 throw InputError("infer_quick_model: servers must have one entry per station");
72 if (!jobs.empty() && jobs.size() != K)
73 throw InputError("infer_quick_model: jobs must have one entry per class");
74 if (!is_open && !routing.empty()) {
75 if (routing.size() != K)
76 throw InputError("infer_quick_model: routing must have one matrix per class");
77 for (const Matrix<T>& P : routing)
78 if (P.rows() != M || P.cols() != M)
79 throw InputError("infer_quick_model: each routing matrix must be M x M");
80 }
81
82 qn::Network<T> model("quickModel");
83 std::size_t source = 0, sink = 0;
84 if (is_open) {
85 source = model.add_source("mySource");
86 sink = model.add_sink("mySink");
87 }
88
89 std::vector<std::size_t> queue(M);
90 for (std::size_t i = 0; i < M; ++i) {
91 queue[i] = model.add_queue("QueueStation" + std::to_string(i + 1), stations[i]);
92 model.set_number_of_servers(queue[i], servers.empty() ? 1.0 : servers[i]);
93 model.set_capacity(queue[i], std::numeric_limits<double>::infinity());
94 }
95
96 std::vector<std::size_t> cls(K);
97 for (std::size_t c = 0; c < K; ++c) {
98 const std::string nm = "Class" + std::to_string(c + 1);
99 cls[c] = is_open ? model.add_open_class(nm)
100 : model.add_closed_class(nm, jobs.empty() ? 1.0 : jobs[c], queue[0]);
101 for (std::size_t i = 0; i < M; ++i)
102 model.set_service(queue[i], cls[c], lang::Distrib<T>::exp_mean(demands(c, i)));
103 }
104
105 const T zero = num_traits<T>::from_int(0);
106 const T one = num_traits<T>::from_int(1);
108 for (std::size_t c = 0; c < K; ++c) {
109 const std::size_t r = cls[c];
110 if (is_open) {
111 P.set(r, r, source, queue[0], one);
112 for (std::size_t i = 0; i + 1 < M; ++i) P.set(r, r, queue[i], queue[i + 1], one);
113 P.set(r, r, queue[M - 1], sink, one);
114 } else if (!routing.empty()) {
115 for (std::size_t i = 0; i < M; ++i)
116 for (std::size_t j = 0; j < M; ++j)
117 if (routing[c](i, j) > zero) P.set(r, r, queue[i], queue[j], routing[c](i, j));
118 } else {
119 for (std::size_t i = 0; i < M; ++i) P.set(r, r, queue[i], queue[(i + 1) % M], one);
120 }
121 }
122 model.link(P);
123 return model;
124}
125
126} // namespace infer
127} // namespace line
128
129#endif // LINE_API_INFER_INFER_QUICK_MODEL_H
InputError(const std::string &what)
Definition error.h:39
std::size_t cols() const
Definition matrix.h:90
std::size_t rows() const
Definition matrix.h:89
A queueing network under construction.
std::size_t add_source(const std::string &nm)
The external arrival station.
std::size_t add_open_class(const std::string &nm, int prio=0)
An open class.
RoutingMatrix< T > init_routing_matrix() const
An empty routing matrix, MATLAB's model.initRoutingMatrix.
void set_number_of_servers(std::size_t node, double n)
queue.setNumberOfServers(n).
std::size_t add_queue(const std::string &nm, SchedStrategy sched=SchedStrategy::FCFS)
A queueing station.
std::size_t add_closed_class(const std::string &nm, double njobs, std::size_t refstat_node, int prio=0)
A closed class of the given population, referencing a station node.
std::size_t add_sink(const std::string &nm)
The external departure node.
void set_capacity(std::size_t node, double k)
station.setCapacity(k), the K of Kendall's notation.
void link(const RoutingMatrix< T > &Pm)
model.link(P): install the routing.
void set_service(std::size_t node, std::size_t cls, const Distrib< T > &d)
station.setService(class, dist).
The routing matrix a model script fills in, MATLAB's P cell array.
void set(std::size_t r, std::size_t s, std::size_t i, std::size_t j, const T &p)
The exception types the port throws.
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
Dense matrix and non-owning view.
qn::Network< T > infer_quick_model(bool is_open, const std::vector< lang::SchedStrategy > &stations, const Matrix< T > &demands, const std::vector< double > &servers=std::vector< double >(), const std::vector< double > &jobs=std::vector< double >(), const std::vector< Matrix< T > > &routing=std::vector< Matrix< T > >())
Build a simple open or closed queueing network.
Conservation laws of a layered queueing network, enumerated from its structure.
Definition aoi_dist2ph.h:52
The Network constructor API: Queue, Delay, Source, Sink, Router, ClassSwitch, Cache,...
Number-type abstraction for the templated API port.
static Distrib exp_mean(const T &m)
Definition lang_types.h:930