LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
solver.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_SOLVERS_SOLVER_H
6#define LINE_SOLVERS_SOLVER_H
7
8/**
9 * @file
10 * @ingroup line_solvers
11 * @ingroup line_public
12 * The solver API a user writes, spelled as its Python twin.
13 *
14 * SolverMVA s(model, "lin");
15 * AvgTable t = s.avg_table();
16 *
17 * against Python's
18 *
19 * s = MVA(model, method='lin')
20 * t = s.avg_table()
21 *
22 * NAMING. A multi-word getter drops the `get_` prefix (`avg_table`,
23 * `tran_avg`, `cdf_respt`), because `line_solver/_aliasing.py` resolves exactly
24 * that spelling onto Python's own `getAvgTable`/`getTranAvg`/`getCdfRespT`; a
25 * SINGLE-word getter keeps it (`get_name`), because that same module
26 * deliberately refuses to expand a bare lowercase word and Python has no
27 * `name()`. So every name here is a name that also resolves in Python.
28 *
29 * IT IS A FACADE, NOT A SOLVER. Every method forwards to the runner the CLI
30 * calls, so a program written against this header and `line-cli` on the same
31 * model answer with the same numbers.
32 *
33 * THESE CLASSES ARE `double`-ONLY AND NOT TEMPLATES, deliberately. The solver
34 * templates are a heavy instantiation and the multiprecision arithmetic has no
35 * Python counterpart, so the bodies are compiled ONCE into `line_mp_api` and a
36 * translation unit including this header pays for none of it. Reach for
37 * `line::mva::solver_mva_run_analyzer` and its siblings directly when you want
38 * another arithmetic.
39 */
40
41#include <cstddef>
42#include <string>
43#include <vector>
44
48#include "line/util/matrix.h"
49
50namespace line {
51
52/** `Network` as a user names it: the `double` model, Python's `Network`. */
54/** `model.init_routing_matrix()`'s type, Python's `RoutingMatrix`. */
56
57/**
58 * The shared surface of every solver, Python's `NetworkSolver`.
59 *
60 * The solve is performed on first demand and cached, which is what
61 * `hasResults`/`is_solved` reports; `reset()` discards it.
62 */
64 public:
65 virtual ~NetworkSolver() {}
66
67 /** `getName()`: the solver's own name, e.g. "MVA". */
68 const std::string& get_name() const { return name_; }
69 /** The options this solver was built with. */
70 const SolverOptions& options() const { return opts_; }
71 /** The model this solver was built on. */
72 Network& model() const { return *model_; }
73
74 /** `getAvgTable()`: the average table, solving on first demand. */
75 const AvgTable& avg_table();
76 /** `getAvgSysTable()`: the per-class system columns of the same solve. */
77 const AvgTable& avg_sys_table() { return avg_table(); }
78 /** `runAnalyzer()`: force the solve, returning the table it produced. */
79 const AvgTable& run_analyzer() { return avg_table(); }
80 /** `listValidMethods()`: the methods this solver advertises on this model. */
81 std::vector<std::string> list_valid_methods() const;
82 /** `isSolved()` / `hasResults()`: whether a solve has been performed. */
83 bool is_solved() const { return solved_; }
84 /** `reset()`: discard the cached solve. */
85 void reset() { solved_ = false; table_ = AvgTable(); }
86 /** `getMethodUsed()`: the method the solve actually resolved to. */
87 std::string method_used();
88
89 protected:
90 NetworkSolver(Network& m, const std::string& name, const SolverOptions& o)
91 : model_(&m), name_(name), opts_(o) {}
92
94 std::string name_;
97 bool solved_ = false;
98};
99
100/**
101 * Every solver takes the model and either a method name or a full option set,
102 * mirroring Python's `SolverX(model, method_or_options=None, **kwargs)`.
103 */
104#define LINE_DECLARE_SOLVER(Cls, tag) \
105 class Cls : public NetworkSolver { \
106 public: \
107 explicit Cls(Network& m, const SolverOptions& o = SolverOptions()) \
108 : NetworkSolver(m, tag, o) {} \
109 Cls(Network& m, const std::string& method) \
110 : NetworkSolver(m, tag, SolverOptions().set_method(method)) {} \
111 }
112
113LINE_DECLARE_SOLVER(SolverMVA, "MVA");
114LINE_DECLARE_SOLVER(SolverNC, "NC");
115LINE_DECLARE_SOLVER(SolverMAM, "MAM");
116LINE_DECLARE_SOLVER(SolverSSA, "SSA");
117LINE_DECLARE_SOLVER(SolverLDES, "LDES");
118LINE_DECLARE_SOLVER(SolverAUTO, "AUTO");
119
120#undef LINE_DECLARE_SOLVER
121
122/**
123 * `SolverJMT`: the Java Modelling Tools client, which also answers a
124 * transient, a response-time law, a state probability and a trajectory.
125 *
126 * IT IS NOT A BARE `LINE_DECLARE_SOLVER`, and the difference is the point: the
127 * macro exposes averages alone, so a program holding a `SolverJMT` could reach
128 * `getAvgTable` and nothing else while `jmt_logs.h` implemented all four of
129 * these and `line-cli -s jmt` reached none of them either.
130 *
131 * EVERY ONE OF THEM IS READ OFF A LOGGED RUN, so each is a `jsim` answer
132 * whatever `--method` asked for: JMVA computes means from a product form and
133 * logs no trajectory at all.
134 */
135class SolverJMT : public NetworkSolver {
136 public:
137 explicit SolverJMT(Network& m, const SolverOptions& o = SolverOptions())
138 : NetworkSolver(m, "JMT", o) {}
139 SolverJMT(Network& m, const std::string& method)
140 : NetworkSolver(m, "JMT", SolverOptions().set_method(method)) {}
141
142 /** `getCdfRespT()`: the EMPIRICAL response-time CDF per (station, class). */
143 std::vector<std::vector<CdfCurve> > cdf_respt();
144
145 /**
146 * `getTranAvg()`: E[N](t), averaged over `options.config.replications`
147 * (`SolverOptions::replications`, default 10) independent replications
148 * under method `default`; an explicit `jsim` is one run.
149 *
150 * A FINITE HORIZON IS REQUIRED (`options.timespan`): a transient mean over
151 * an unstated horizon is not a quantity, and it is also what makes the
152 * replications' event grids commensurable.
153 */
155
156 /** `getProbAggr(node, state)`: the time the declared state is held for. */
157 double prob_aggr(std::size_t node, const std::vector<double>& state);
158
159 /**
160 * `sampleSysAggr(events)`, or `sampleAggr(node, events)` when `node` is
161 * given: one logged trajectory.
162 *
163 * `events` TRUNCATES, it does not stop the run: JMT's `maxEvents` is
164 * global and cannot be asked for a count at one node, so what comes back is
165 * a prefix of the run the engine produced. Zero returns all of it.
166 */
167 SamplePath sample(std::size_t events = 0, std::size_t node = 0);
168};
169
170/** `SolverCTMC`: the average table plus the chain it was computed from. */
171class SolverCTMC : public NetworkSolver {
172 public:
174 : NetworkSolver(m, "CTMC", o) {}
175 SolverCTMC(Network& m, const std::string& method)
176 : NetworkSolver(m, "CTMC", SolverOptions().set_method(method)) {}
177
178 /** `getStateSpace()`: the aggregate state space, one row per state. */
180 /** `getGenerator()`: the infinitesimal generator over that space. */
182 /** `getProbAggr(node, state)`: the aggregate marginal of one state. */
183 double prob_aggr(std::size_t node, const std::vector<double>& state);
184 /** `getProbStateAggr(node)`: the marginal over every state of one station. */
185 std::vector<double> marg_aggr(std::size_t node);
186 /** `getCdfRespT()`: the response-time CDF per (station, class). */
187 std::vector<std::vector<CdfCurve> > cdf_respt();
188
189 /**
190 * `getSymbolicSolution()`: the stationary law over the rate symbols x1..xE.
191 *
192 * The generator itself needs no computer algebra, being linear in the
193 * symbols, but solving pi Q = 0 over the field of rational functions does,
194 * and that is delegated to the backend `options.symbolic` names. Throws
195 * when no backend can be resolved rather than returning a numeric answer
196 * under a symbolic name.
197 */
199
200 /** `CTMC.printInfGen(Q, SS)`: the generator beside the state it belongs to. */
201 static void print_inf_gen(const Matrix<double>& Q, const Matrix<double>& space);
202};
203
204/** `SolverFLD`: the fluid solver, which also answers a transient. */
205class SolverFLD : public NetworkSolver {
206 public:
207 explicit SolverFLD(Network& m, const SolverOptions& o = SolverOptions())
208 : NetworkSolver(m, "FLD", o) {}
209 SolverFLD(Network& m, const std::string& method)
210 : NetworkSolver(m, "FLD", SolverOptions().set_method(method)) {}
211
212 /** `getTranAvg()`: the transient mean queue length per station. */
214 /** `getCdfRespT()`: the response-time CDF per (station, class). */
215 std::vector<std::vector<CdfCurve> > cdf_respt();
216};
217
218/** `SolverBA`: the bounding solver, whose result is a bounds table. */
219class SolverBA : public NetworkSolver {
220 public:
221 explicit SolverBA(Network& m, const SolverOptions& o = SolverOptions())
222 : NetworkSolver(m, "BA", o) {}
223 SolverBA(Network& m, const std::string& method)
224 : NetworkSolver(m, "BA", SolverOptions().set_method(method)) {}
225
226 /** `getBoundsTable()`: the per-class queue-length and throughput bounds. */
228};
229
230// Python's short aliases: `MVA(model)` is `SolverMVA(model)`.
231typedef SolverMVA MVA;
232typedef SolverNC NC;
234typedef SolverSSA SSA;
237typedef SolverMAM MAM;
239typedef SolverLDES LDES;
240typedef SolverAUTO AUTO;
241typedef SolverBA BA;
242
243} // namespace line
244
245#endif // LINE_SOLVERS_SOLVER_H
The result tables a solver returns.
const AvgTable & avg_sys_table()
getAvgSysTable(): the per-class system columns of the same solve.
Definition solver.h:77
AvgTable table_
Definition solver.h:96
const SolverOptions & options() const
The options this solver was built with.
Definition solver.h:70
const std::string & get_name() const
getName(): the solver's own name, e.g.
Definition solver.h:68
SolverOptions opts_
Definition solver.h:95
std::string method_used()
getMethodUsed(): the method the solve actually resolved to.
const AvgTable & run_analyzer()
runAnalyzer(): force the solve, returning the table it produced.
Definition solver.h:79
Network * model_
Definition solver.h:93
std::vector< std::string > list_valid_methods() const
listValidMethods(): the methods this solver advertises on this model.
const AvgTable & avg_table()
getAvgTable(): the average table, solving on first demand.
virtual ~NetworkSolver()
Definition solver.h:65
bool is_solved() const
isSolved() / hasResults(): whether a solve has been performed.
Definition solver.h:83
Network & model() const
The model this solver was built on.
Definition solver.h:72
void reset()
reset(): discard the cached solve.
Definition solver.h:85
NetworkSolver(Network &m, const std::string &name, const SolverOptions &o)
Definition solver.h:90
std::string name_
Definition solver.h:94
SolverBA: the bounding solver, whose result is a bounds table.
Definition solver.h:219
BoundsTable bounds_table()
getBoundsTable(): the per-class queue-length and throughput bounds.
SolverBA(Network &m, const std::string &method)
Definition solver.h:223
SolverBA(Network &m, const SolverOptions &o=SolverOptions())
Definition solver.h:221
SolverCTMC: the average table plus the chain it was computed from.
Definition solver.h:171
static void print_inf_gen(const Matrix< double > &Q, const Matrix< double > &space)
CTMC.printInfGen(Q, SS): the generator beside the state it belongs to.
Matrix< double > generator()
getGenerator(): the infinitesimal generator over that space.
double prob_aggr(std::size_t node, const std::vector< double > &state)
getProbAggr(node, state): the aggregate marginal of one state.
Matrix< double > state_space()
getStateSpace(): the aggregate state space, one row per state.
SolverCTMC(Network &m, const SolverOptions &o=SolverOptions())
Definition solver.h:173
SymbolicSolution symbolic_solution()
getSymbolicSolution(): the stationary law over the rate symbols x1..xE.
std::vector< double > marg_aggr(std::size_t node)
getProbStateAggr(node): the marginal over every state of one station.
std::vector< std::vector< CdfCurve > > cdf_respt()
getCdfRespT(): the response-time CDF per (station, class).
SolverCTMC(Network &m, const std::string &method)
Definition solver.h:175
SolverFLD: the fluid solver, which also answers a transient.
Definition solver.h:205
SolverFLD(Network &m, const std::string &method)
Definition solver.h:209
std::vector< std::vector< CdfCurve > > cdf_respt()
getCdfRespT(): the response-time CDF per (station, class).
TranAvg tran_avg()
getTranAvg(): the transient mean queue length per station.
SolverFLD(Network &m, const SolverOptions &o=SolverOptions())
Definition solver.h:207
SolverJMT: the Java Modelling Tools client, which also answers a transient, a response-time law,...
Definition solver.h:135
TranAvg tran_avg()
getTranAvg(): E[N](t), averaged over options.config.replications (SolverOptions::replications,...
SolverJMT(Network &m, const SolverOptions &o=SolverOptions())
Definition solver.h:137
SamplePath sample(std::size_t events=0, std::size_t node=0)
sampleSysAggr(events), or sampleAggr(node, events) when node is given: one logged trajectory.
SolverJMT(Network &m, const std::string &method)
Definition solver.h:139
std::vector< std::vector< CdfCurve > > cdf_respt()
getCdfRespT(): the EMPIRICAL response-time CDF per (station, class).
double prob_aggr(std::size_t node, const std::vector< double > &state)
getProbAggr(node, state): the time the declared state is held for.
A queueing network under construction.
The routing matrix a model script fills in, MATLAB's P cell array.
Dense matrix and non-owning view.
Conservation laws of a layered queueing network, enumerated from its structure.
Definition aoi_dist2ph.h:52
SolverSSA SSA
Definition solver.h:234
SolverAUTO AUTO
Definition solver.h:240
SolverBA BA
Definition solver.h:241
qn::RoutingMatrix< double > RoutingMatrix
model.init_routing_matrix()'s type, Python's RoutingMatrix.
Definition solver.h:55
SolverMAM MAM
Definition solver.h:237
qn::Network< double > Network
Network as a user names it: the double model, Python's Network.
Definition solver.h:53
SolverFLD FLD
Definition solver.h:235
SolverLDES LDES
Definition solver.h:239
SolverNC NC
Definition solver.h:232
SolverFLD SolverFluid
Definition solver.h:236
SolverCTMC CTMC
Definition solver.h:233
SolverJMT JMT
Definition solver.h:238
SolverMVA MVA
Definition solver.h:231
LINE_DECLARE_SOLVER(SolverMVA, "MVA")
The Network constructor API: Queue, Delay, Source, Sink, Router, ClassSwitch, Cache,...
The keyword arguments a solver takes, as one struct.
getAvgTable, one row per (station, class) that carries a metric.
Definition avg_table.h:38
SolverBA(model, method).getBoundsTable().
Definition avg_table.h:95
sampleSysAggr / sampleAggr: ONE simulated trajectory, not a mean.
Definition avg_table.h:138
The knobs a solver reads; a negative or empty field keeps the engine default.
getSymbolicSolution: the stationary law as a function of the rate symbols.
Definition avg_table.h:114
getTranAvg: the transient mean queue length per (station, class).
Definition avg_table.h:124