LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
ctmc_ssg.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_MC_CTMC_SSG_H
6#define LINE_API_MC_CTMC_SSG_H
7
8/**
9 * @file
10 * @ingroup api_mc
11 * Ports of matlab/src/api/mc/ctmc_ssg.m and ctmc_ssg_reachability.m: the
12 * state space of a network as SolverCTMC enumerates it, in the reference's
13 * three views.
14 *
15 * stateSpace one row per network state, the per-node local rows
16 * concatenated in stateful-node order
17 * stateSpaceAggr (nstates x nstations*nclasses), the per-station job
18 * counts of each state (`State.toMarginal`)
19 * stateSpaceHashed (nstates x nstateful), the 1-based row of each node's
20 * local space that the state occupies
21 * nodeStateSpace the per-node local spaces the hashes index into, the
22 * reference's `sn.space`
23 *
24 * The reference writes `nodeStateSpace` back onto `sn.space` and returns the
25 * struct; this NetworkStruct carries no `space` member (the analyzer rebuilds
26 * it per solve), so the node spaces are returned on the result instead.
27 *
28 * `ctmc_ssg` is the FULL enumeration (`State.spaceGenerator`): every state the
29 * encoding admits, reachable or not. The reference refuses a fork-join model
30 * here, because a Fork firing does not conserve the per-chain population the
31 * lattice walks; `ctmc_ssg_reachability` is the reachable walk
32 * (`State.reachableSpaceGenerator`) from the model's initial state, which is
33 * the one those models need.
34 *
35 * The enumeration itself is `qn::space_generator` and
36 * `ctmc::reachable_space_generator`, shared with SolverCTMC, so a space listed
37 * here is the space the solver solves.
38 */
39
40#include <cstddef>
41#include <map>
42#include <vector>
43
45#include "line/lang/qn/state.h"
47#include "line/num/number.h"
50#include "line/util/error.h"
51#include "line/util/matrix.h"
52
53namespace line {
54namespace mc {
55
56/** The reference's options read here: `options.cutoff` and the state cap. */
58 /** Per-class population bound for the open classes (`options.cutoff`); 0 = closed. */
59 std::vector<std::size_t> cutoff;
60 /** Optional (nstations x nclasses) bound, the reference's matrix `options.cutoff`. */
61 std::vector<std::vector<std::size_t>> cutoff_mat;
62 /** Refuse beyond this many states (the reference's ctmc_max_states). */
63 std::size_t state_max = 3000000;
64};
65
66/** The reference's `[stateSpace, stateSpaceAggr, stateSpaceHashed, nodeStateSpace]`. */
67template <class T>
71 /** 1-based row of `node_state_space[isf]` each state occupies at node isf. */
72 std::vector<std::vector<std::size_t>> state_space_hashed;
73 /** One local space per stateful node, rows in first-seen order. */
74 std::vector<Matrix<T>> node_state_space;
75 /** The enumerated states as the solvers consume them (port-only convenience). */
76 std::vector<qn::NetState<T>> space;
77};
78
79namespace ssg_detail {
80
81/** The three matrix views from an enumerated space. */
82template <class T>
84 const T zero = num_traits<T>::from_int(0);
85 const std::size_t S = sn.nof_stateful();
87
88 // per-node local spaces and the hash of every state into them
89 std::vector<std::map<std::vector<T>, std::size_t>> seen(S);
90 std::vector<std::vector<std::vector<T>>> rows(S);
91 out.state_space_hashed.assign(space.size(), std::vector<std::size_t>(S, 0));
92 std::size_t width = 0;
93 for (std::size_t st = 0; st < space.size(); ++st) {
94 std::size_t w = 0;
95 for (std::size_t f = 0; f < S && f < space[st].local.size(); ++f) {
96 const std::vector<T>& loc = space[st].local[f];
97 w += loc.size();
98 typename std::map<std::vector<T>, std::size_t>::const_iterator it = seen[f].find(loc);
99 if (it == seen[f].end()) {
100 rows[f].push_back(loc);
101 seen[f][loc] = rows[f].size(); // 1-based
102 out.state_space_hashed[st][f] = rows[f].size();
103 } else {
104 out.state_space_hashed[st][f] = it->second;
105 }
106 }
107 if (w > width) width = w;
108 }
109 out.node_state_space.resize(S);
110 for (std::size_t f = 0; f < S; ++f) {
111 const std::size_t nr = rows[f].size();
112 std::size_t nc = 0;
113 for (std::size_t a = 0; a < nr; ++a) nc = std::max(nc, rows[f][a].size());
114 out.node_state_space[f] = Matrix<T>(nr, nc, zero);
115 for (std::size_t a = 0; a < nr; ++a)
116 for (std::size_t b = 0; b < rows[f][a].size(); ++b)
117 out.node_state_space[f](a, b) = rows[f][a][b];
118 }
119
120 // stateSpace: the local rows side by side, in stateful-node order
121 out.state_space = Matrix<T>(space.size(), width, zero);
122 for (std::size_t st = 0; st < space.size(); ++st) {
123 std::size_t col = 0;
124 for (std::size_t f = 0; f < space[st].local.size(); ++f)
125 for (std::size_t b = 0; b < space[st].local[f].size(); ++b)
126 out.state_space(st, col++) = space[st].local[f][b];
127 }
128
129 // stateSpaceAggr: the per-station marginal job counts (State.toMarginal)
131 out.space = std::move(space);
132 return out;
133}
134
135inline std::vector<std::size_t> cutoff_or_closed(const std::vector<std::size_t>& cutoff,
136 std::size_t R) {
137 if (cutoff.size() == R) return cutoff;
138 if (cutoff.empty()) return std::vector<std::size_t>(R, 0);
139 if (cutoff.size() == 1) return std::vector<std::size_t>(R, cutoff[0]);
140 throw InputError("ctmc_ssg: options.cutoff must hold one entry per class");
141}
142
143} // namespace ssg_detail
144
145/**
146 * Port of `ctmc_ssg`: the FULL state space of the network.
147 *
148 * @param sn the refreshed network struct
149 * @param options the cutoff of the open classes and the state cap
150 * @param fjsync the fork firing list; a non-empty one is refused, as the
151 * reference refuses a model with `sn.fjsync`
152 */
153template <class T>
155 const CtmcSsgOptions& options = CtmcSsgOptions(),
156 const std::vector<qn::FjSync<T>>& fjsync = std::vector<qn::FjSync<T>>()) {
157 if (!fjsync.empty())
158 throw UnsupportedError(ErrorKind{"Fork"},
159 "ctmc_ssg: Fork-join models require reachability-based state space generation "
160 "(options.config.state_space_gen='reachable').");
161 const std::vector<std::size_t> cutoff =
162 ssg_detail::cutoff_or_closed(options.cutoff, sn.nclasses);
163 std::vector<qn::NetState<T>> space =
164 qn::space_generator(sn, cutoff, options.state_max, options.cutoff_mat);
165 return ssg_detail::assemble(sn, std::move(space));
166}
167
168/**
169 * Port of `ctmc_ssg_reachability`: the REACHABLE state space, walked from the
170 * model's initial state over the synchronizations `refresh_sync` and
171 * `refresh_global_sync` build.
172 *
173 * @param sn the refreshed network struct
174 * @param options the cutoff of the open classes and the state cap
175 * @param fjsync the fork firing list of a fork-join model, empty otherwise
176 */
177template <class T>
179 const qn::NetworkStruct<T>& sn, const CtmcSsgOptions& options = CtmcSsgOptions(),
180 const std::vector<qn::FjSync<T>>& fjsync = std::vector<qn::FjSync<T>>()) {
181 qn::NetState<T> init;
182 if (!ctmc::analyzer_detail::default_init_state(sn, init))
183 throw UnsupportedError(ErrorKind{"Model"},
184 "ctmc_ssg_reachability: the model's initial marking admits no state; check the Place "
185 "populations against the class reference stations");
186 const std::vector<std::size_t> cutoff =
187 ssg_detail::cutoff_or_closed(options.cutoff, sn.nclasses);
188 const std::vector<qn::Sync<T>> sync = qn::refresh_sync(sn);
189 const std::vector<qn::GlobalSync<T>> gsync = qn::refresh_global_sync(sn);
190 std::vector<qn::NetState<T>> space = ctmc::reachable_space_generator(
191 sn, init, sync, gsync, options.state_max, fjsync, cutoff, options.cutoff_mat);
192 return ssg_detail::assemble(sn, std::move(space));
193}
194
195} // namespace mc
196} // namespace line
197
198#endif // LINE_API_MC_CTMC_SSG_H
InputError(const std::string &what)
Definition error.h:105
UnsupportedError(const std::string &what)
Definition error.h:119
A network plus its refreshed NetworkStruct.
The exception types the port throws.
Dense matrix and non-owning view.
Matrix< T > ctmc_state_space_aggr(const NetworkStruct< T > &sn, const std::vector< NetState< T > > &space)
Port of StateSpaceAggr: the per-(station, class) job counts of every state, as an (nstates x nstation...
std::vector< NetState< T > > reachable_space_generator(const NetworkStruct< T > &sn, const NetState< T > &init, const std::vector< Sync< T > > &sync, const std::vector< qn::GlobalSync< T > > &gsync=std::vector< qn::GlobalSync< T > >(), std::size_t maxst=3000000, const std::vector< qn::FjSync< T > > &fjsync=std::vector< qn::FjSync< T > >(), const std::vector< std::size_t > &cutoff=std::vector< std::size_t >(), const std::vector< std::vector< std::size_t > > &cutoff_mat=std::vector< std::vector< std::size_t > >())
Port of State.reachableSpaceGenerator: the states reachable from init.
CtmcSsgResult< T > assemble(const qn::NetworkStruct< T > &sn, std::vector< qn::NetState< T > > space)
The three matrix views from an enumerated space.
Definition ctmc_ssg.h:83
std::vector< std::size_t > cutoff_or_closed(const std::vector< std::size_t > &cutoff, std::size_t R)
Definition ctmc_ssg.h:135
CtmcSsgResult< T > ctmc_ssg_reachability(const qn::NetworkStruct< T > &sn, const CtmcSsgOptions &options=CtmcSsgOptions(), const std::vector< qn::FjSync< T > > &fjsync=std::vector< qn::FjSync< T > >())
Port of ctmc_ssg_reachability: the REACHABLE state space, walked from the model's initial state over ...
Definition ctmc_ssg.h:178
CtmcSsgResult< T > ctmc_ssg(const qn::NetworkStruct< T > &sn, const CtmcSsgOptions &options=CtmcSsgOptions(), const std::vector< qn::FjSync< T > > &fjsync=std::vector< qn::FjSync< T > >())
Port of ctmc_ssg: the FULL state space of the network.
Definition ctmc_ssg.h:154
std::vector< NetState< T > > space_generator(const NetworkStruct< T > &sn, const std::vector< std::size_t > &cutoff, std::size_t maxst=3000000, const std::vector< std::vector< std::size_t > > &cutoff_mat=std::vector< std::vector< std::size_t > >())
Port of State.spaceGenerator: every network state, reachable or not.
Definition state.h:2907
std::vector< Sync< T > > refresh_sync(const NetworkStruct< T > &sn, const std::vector< std::vector< bool > > &impatience_classes=std::vector< std::vector< bool > >(), const std::vector< std::size_t > &breakdown_nodes=std::vector< std::size_t >())
Port of MNetwork.refreshSync: the synchronization list.
std::vector< GlobalSync< T > > refresh_global_sync(const NetworkStruct< T > &sn)
Port of MNetwork.refreshGlobalSync: the ENABLE and FIRE synchronizations.
Conservation laws of a layered queueing network, enumerated from its structure.
Definition aoi_dist2ph.h:52
A queueing network and its refreshed NetworkStruct.
Number-type abstraction for the templated API port.
Port of solver_ctmc.m: the infinitesimal generator of a queueing network, assembled from the enumerat...
Port of solver_ctmc_analyzer.m and the parts of @@SolverCTMC/runAnalyzer.m that surround one solve: t...
Port of the MATLAB +State package: the encoding that turns a station's state row into marginal job co...
Port of the event half of MATLAB's +State package: the successor states an event produces at one node...
The <kind> part of a LINE:<category>:<kind> identifier (see _kb/17-error-vocabulary....
Definition error.h:37
The reference's options read here: options.cutoff and the state cap.
Definition ctmc_ssg.h:57
std::vector< std::size_t > cutoff
Per-class population bound for the open classes (options.cutoff); 0 = closed.
Definition ctmc_ssg.h:59
std::vector< std::vector< std::size_t > > cutoff_mat
Optional (nstations x nclasses) bound, the reference's matrix options.cutoff.
Definition ctmc_ssg.h:61
std::size_t state_max
Refuse beyond this many states (the reference's ctmc_max_states).
Definition ctmc_ssg.h:63
The reference's [stateSpace, stateSpaceAggr, stateSpaceHashed, nodeStateSpace].
Definition ctmc_ssg.h:68
Matrix< T > state_space_aggr
Definition ctmc_ssg.h:70
Matrix< T > state_space
Definition ctmc_ssg.h:69
std::vector< qn::NetState< T > > space
The enumerated states as the solvers consume them (port-only convenience).
Definition ctmc_ssg.h:76
std::vector< Matrix< T > > node_state_space
One local space per stateful node, rows in first-seen order.
Definition ctmc_ssg.h:74
std::vector< std::vector< std::size_t > > state_space_hashed
1-based row of node_state_space[isf] each state occupies at node isf.
Definition ctmc_ssg.h:72
One fork firing synchronization: sn.fjsync{k}.
One network state: the per-stateful-node local rows it is composed of.
Definition state.h:2734