LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
sn_print.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_SN_SN_PRINT_H
6#define LINE_API_SN_SN_PRINT_H
7
8/**
9 * @file
10 * @ingroup api_sn
11 * Port of matlab/src/api/sn/sn_print.m, jline.api.sn.SnPrint and the python
12 * `sn_print` in api/sn/utils.py: the full debug dump of a NetworkStruct, one
13 * `field: value` line per field, matrices in the compact `[a b; c d]` form,
14 * integer-valued entries printed as integers.
15 *
16 * The field list is this port's own: the C++ NetworkStruct is object-shaped
17 * (per-station and per-class records instead of MATLAB's flat matrices), so
18 * the dump renders the MATLAB fields it can derive (refstat, njobs, nservers,
19 * phases, chains, ...) in the reference's order and naming, then the
20 * structural members that only exist here (station_to_node, stateful_nodes).
21 * MATLAB fields with no counterpart in this port (connmatrix, spaceHash) are
22 * omitted rather than printed empty; `network_struct.h` documents why each is
23 * absent.
24 *
25 * Returned as a string rather than printed, so a caller can route it to a
26 * log, a CLI or a test, following `sn_print_routing_matrix`.
27 *
28 * ARITHMETIC: field, but the rendering is in double.
29 */
30
31#include <cmath>
32#include <cstddef>
33#include <cstdio>
34#include <limits>
35#include <string>
36#include <vector>
37
40#include "line/num/number.h"
41#include "line/util/matrix.h"
42
43namespace line {
44namespace api {
45
46namespace sn_print_detail {
47
48/** One number, integer-rendered when it is one, as the reference prints. */
49inline std::string num(double v) {
50 if (std::isnan(v)) return "NaN";
51 if (std::isinf(v)) return v > 0 ? "Inf" : "-Inf";
52 if (v == std::floor(v) && std::fabs(v) < 1e15) {
53 char buf[32];
54 std::snprintf(buf, sizeof(buf), "%lld", static_cast<long long>(v));
55 return buf;
56 }
57 char buf[32];
58 std::snprintf(buf, sizeof(buf), "%g", v);
59 return buf;
60}
61
62/** The compact `[a b; c d]` form of the reference's printMatrixCompact. */
63inline std::string mat(const std::vector<std::vector<double>>& m) {
64 if (m.empty() || m[0].empty()) return "[]";
65 std::string out = "[";
66 for (std::size_t i = 0; i < m.size(); ++i) {
67 if (i > 0) out += "; ";
68 for (std::size_t j = 0; j < m[i].size(); ++j) {
69 if (j > 0) out += " ";
70 out += num(m[i][j]);
71 }
72 }
73 return out + "]";
74}
75
76inline std::string row(const std::vector<double>& v) {
77 return mat(std::vector<std::vector<double>>(1, v));
78}
79
80template <class T>
81std::string tmat(const Matrix<T>& m) {
82 std::vector<std::vector<double>> d(m.rows(), std::vector<double>(m.cols()));
83 for (std::size_t i = 0; i < m.rows(); ++i)
84 for (std::size_t j = 0; j < m.cols(); ++j) d[i][j] = num_traits<T>::to_double(m(i, j));
85 return mat(d);
86}
87
88inline std::string names(const std::vector<std::string>& v) {
89 if (v.empty()) return "[]";
90 std::string out = "[";
91 for (std::size_t i = 0; i < v.size(); ++i) {
92 if (i > 0) out += ", ";
93 out += "\"" + v[i] + "\"";
94 }
95 return out + "]";
96}
97
98} // namespace sn_print_detail
99
100/** The full `field: value` dump of a NetworkStruct, ending with a newline. */
101template <class T>
102std::string sn_print(const qn::NetworkStruct<T>& sn) {
103 using sn_print_detail::mat;
104 using sn_print_detail::names;
105 using sn_print_detail::num;
106 using sn_print_detail::row;
107 using sn_print_detail::tmat;
108 typedef std::vector<double> Row;
109 typedef std::vector<std::vector<double>> Tab;
110 const std::size_t M = sn.nof_stations(), K = sn.nclasses, I = sn.nof_nodes();
111 std::string out;
112
113 out += "nstations: " + num(static_cast<double>(M)) + "\n";
114 out += "nstateful: " + num(static_cast<double>(sn.nof_stateful())) + "\n";
115 out += "nnodes: " + num(static_cast<double>(I)) + "\n";
116 out += "nclasses: " + num(static_cast<double>(K)) + "\n";
117 out += "nclosedjobs: " + num(sn.nclosedjobs()) + "\n";
118 out += "nchains: " + num(static_cast<double>(sn.nchains)) + "\n";
119
120 Row refstat(K), njobsv = sn.njobs(), classprio(K);
121 for (std::size_t r = 0; r < K; ++r) {
122 refstat[r] = static_cast<double>(sn.classes[r].refstat);
123 classprio[r] = static_cast<double>(sn.classes[r].prio);
124 }
125 out += "refstat: " + row(refstat) + "\n";
126 out += "njobs: " + row(njobsv) + "\n";
127 Row nservers(M), cap(M);
128 Tab classcap(M, Row(K)), phases(M, Row(K)), schedparam(M, Row(K, 0.0));
129 Tab droprule(M, Row(K)), procid(M, Row(K));
130 for (std::size_t i = 0; i < M; ++i) {
131 nservers[i] = sn.stations[i].nservers;
132 cap[i] = i < sn.cap.size() ? sn.cap[i] : std::numeric_limits<double>::infinity();
133 for (std::size_t r = 0; r < K; ++r) {
134 classcap[i][r] = i < sn.classcap.size() && r < sn.classcap[i].size()
135 ? sn.classcap[i][r]
136 : std::numeric_limits<double>::infinity();
137 phases[i][r] = static_cast<double>(sn.phases_of(i + 1, r + 1));
138 if (r < sn.stations[i].schedparam.size())
139 schedparam[i][r] = num_traits<T>::to_double(sn.stations[i].schedparam[r]);
140 droprule[i][r] = i < sn.droprule.size() && r < sn.droprule[i].size()
141 ? static_cast<double>(static_cast<int>(sn.droprule[i][r]))
142 : static_cast<double>(static_cast<int>(qn::DropStrategy::WAITQ));
143 procid[i][r] = static_cast<double>(static_cast<int>(sn.procid(i + 1, r + 1)));
144 }
145 }
146 out += "nservers: " + row(nservers) + "\n";
147 out += "rates: " + tmat(sn.rates) + "\n";
148 out += "scv: " + tmat(sn.scv) + "\n";
149 out += "classprio: " + row(classprio) + "\n";
150 out += "phases: " + mat(phases) + "\n";
151 out += "schedparam: " + mat(schedparam) + "\n";
152
153 Tab chains(sn.chains.size());
154 for (std::size_t c = 0; c < sn.chains.size(); ++c)
155 for (std::size_t r = 0; r < sn.chains[c].size(); ++r)
156 chains[c].push_back(sn.chains[c][r] ? 1.0 : 0.0);
157 out += "chains: " + mat(chains) + "\n";
158 out += "rt: " + tmat(sn.rt) + "\n";
159 out += "rtnodes: " + tmat(sn.rtnodes) + "\n";
160
161 Tab nvars(sn.nvars.size());
162 for (std::size_t i = 0; i < sn.nvars.size(); ++i)
163 for (std::size_t v = 0; v < sn.nvars[i].size(); ++v)
164 nvars[i].push_back(static_cast<double>(sn.nvars[i][v]));
165 out += "nvars: " + mat(nvars) + "\n";
166 out += "cap: " + row(cap) + "\n";
167 out += "classcap: " + mat(classcap) + "\n";
168
169 Row refclass(sn.refclass.size());
170 for (std::size_t c = 0; c < sn.refclass.size(); ++c)
171 refclass[c] = static_cast<double>(sn.refclass[c]);
172 out += "refclass: " + row(refclass) + "\n";
173
174 Tab lld;
175 for (std::size_t i = 0; i < M; ++i)
176 if (!sn.stations[i].lldscaling.empty()) {
177 Row rw;
178 for (std::size_t n = 0; n < sn.stations[i].lldscaling.size(); ++n)
179 rw.push_back(num_traits<T>::to_double(sn.stations[i].lldscaling[n]));
180 lld.push_back(rw);
181 }
182 out += "lldscaling: " + (lld.empty() ? std::string("[]") : mat(lld)) + "\n";
183
184 Tab fj(sn.fj.size());
185 for (std::size_t e = 0; e < sn.fj.size(); ++e) {
186 fj[e].push_back(static_cast<double>(sn.fj[e].first));
187 fj[e].push_back(static_cast<double>(sn.fj[e].second));
188 }
189 out += "fj: " + mat(fj) + "\n";
190
191 out += "nodetype: ";
192 if (sn.nodes.empty()) {
193 out += "[]\n";
194 } else {
195 out += "[";
196 for (std::size_t i = 0; i < I; ++i) {
197 if (i > 0) out += ", ";
198 out += lang::node_type_to_text(sn.nodes[i].nodetype);
199 }
200 out += "]\n";
201 }
202 std::vector<std::string> classnames(K), nodenames(I), schednames(M);
203 for (std::size_t r = 0; r < K; ++r) classnames[r] = sn.classes[r].name;
204 for (std::size_t i = 0; i < I; ++i) nodenames[i] = sn.nodes[i].name;
205 out += "classnames: " + names(classnames) + "\n";
206 out += "nodenames: " + names(nodenames) + "\n";
207
208 out += "sched: {";
209 for (std::size_t i = 0; i < M; ++i) {
210 if (i > 0) out += ", ";
211 out += "\"" + sn.stations[i].name + "\": \"" +
212 lang::sched_to_text(sn.stations[i].sched) + "\"";
213 }
214 out += "}\n";
215
216 out += "procid: " + mat(procid) + "\n";
217 out += "proc: {";
218 for (std::size_t i = 0; i < M; ++i) {
219 if (i > 0) out += ", ";
220 out += "\"" + sn.stations[i].name + "\": {";
221 for (std::size_t r = 0; r < K; ++r) {
222 if (r > 0) out += ", ";
223 const lang::Distrib<T>& d = sn.service[i][r];
224 out += "\"" + sn.classes[r].name + "\": ";
225 if (d.disabled) {
226 out += "null";
227 } else {
228 out += std::string("{\"type\": \"") + lang::process_to_text(d.type) +
229 "\", \"mean\": " + num(num_traits<T>::to_double(d.mean)) +
230 ", \"scv\": " + num(num_traits<T>::to_double(d.scv)) + "}";
231 }
232 }
233 out += "}";
234 }
235 out += "}\n";
236
237 out += "inchain: {";
238 for (std::size_t c = 0; c < sn.inchain.size(); ++c) {
239 if (c > 0) out += ", ";
240 Row rw;
241 for (std::size_t k = 0; k < sn.inchain[c].size(); ++k)
242 rw.push_back(static_cast<double>(sn.inchain[c][k]));
243 out += num(static_cast<double>(c)) + ": " + row(rw);
244 }
245 out += "}\n";
246
247 out += "visits: {";
248 for (std::size_t c = 0; c < sn.visits.size(); ++c) {
249 if (c > 0) out += ", ";
250 out += num(static_cast<double>(c)) + ": " + tmat(sn.visits[c]);
251 }
252 out += "}\n";
253 out += "nodevisits: {";
254 for (std::size_t c = 0; c < sn.nodevisits.size(); ++c) {
255 if (c > 0) out += ", ";
256 out += num(static_cast<double>(c)) + ": " + tmat(sn.nodevisits[c]);
257 }
258 out += "}\n";
259 out += "droprule: " + mat(droprule) + "\n";
260
261 Row s2n(sn.station_to_node.size()), stf(sn.stateful_nodes.size());
262 for (std::size_t i = 0; i < sn.station_to_node.size(); ++i)
263 s2n[i] = static_cast<double>(sn.station_to_node[i]);
264 for (std::size_t i = 0; i < sn.stateful_nodes.size(); ++i)
265 stf[i] = static_cast<double>(sn.stateful_nodes[i]);
266 out += "stationToNode: " + row(s2n) + "\n";
267 out += "statefulNodes: " + row(stf) + "\n";
268
269 out += "csmatrix: {";
270 {
271 bool first = true;
272 for (typename std::map<std::size_t, Matrix<T>>::const_iterator it = sn.csmatrix.begin();
273 it != sn.csmatrix.end(); ++it) {
274 if (!first) out += ", ";
275 first = false;
276 out += num(static_cast<double>(it->first)) + ": " + tmat(it->second);
277 }
278 }
279 out += "}\n";
280 return out;
281}
282
283} // namespace api
284} // namespace line
285
286#endif // LINE_API_SN_SN_PRINT_H
A network plus its refreshed NetworkStruct.
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
Dense matrix and non-owning view.
std::string sn_print(const qn::NetworkStruct< T > &sn)
The full field: value dump of a NetworkStruct, ending with a newline.
Definition sn_print.h:102
const char * node_type_to_text(NodeType t)
Name of a node kind, for diagnostics.
Definition lang_types.h:341
const char * sched_to_text(SchedStrategy s)
Definition lang_types.h:230
const char * process_to_text(ProcessType p)
The MATLAB ProcessType name, as sn.procid prints it.
Definition lang_types.h:560
A queueing network and its refreshed NetworkStruct.
Number-type abstraction for the templated API port.