5#ifndef LINE_SOLVERS_SSA_SOLVER_SSA_GETTERS_H
6#define LINE_SOLVERS_SSA_SOLVER_SSA_GETTERS_H
78 std::vector<double>
t;
86namespace getters_detail {
91 const std::vector<T>& row) {
93 std::vector<double> out(m.second.size(), 0.0);
94 for (std::size_t k = 0; k < m.second.size(); ++k)
101bool same_row(
const std::vector<T>& a,
const std::vector<T>& b) {
102 if (a.size() != b.size())
return false;
103 for (std::size_t j = 0; j < a.size(); ++j)
109inline bool same_counts(
const std::vector<double>& a,
const std::vector<double>& b) {
110 if (a.size() != b.size())
return false;
111 for (std::size_t j = 0; j < a.size(); ++j)
112 if (std::fabs(a[j] - b[j]) > 1e-9)
return false;
124std::string node_label(
const qn::NetworkStruct<T>& sn, std::size_t ind) {
125 if (ind == 0 || ind > sn.nodes.size())
return "#" + std::to_string(ind);
126 return sn.nodes[ind - 1].name;
144 const std::vector<T>& row) {
145 const std::size_t isf =
sn.stateful_index(ind);
147 throw InputError(
"ssa_prob: node '" + getters_detail::node_label(
sn, ind) +
148 "' is stateless, so it has no state to report a probability of");
150 for (std::size_t s = 0; s < r.
space.size(); ++s) {
151 if (!getters_detail::same_row(r.
space[s].local[isf - 1], row))
continue;
161 std::size_t ind,
const std::vector<double>& counts) {
162 const std::size_t isf =
sn.stateful_index(ind);
164 throw InputError(
"ssa_prob_aggr: node '" + getters_detail::node_label(
sn, ind) +
165 "' is stateless, so it holds no jobs to count");
167 for (std::size_t s = 0; s < r.
space.size(); ++s) {
168 if (!getters_detail::same_counts(
169 getters_detail::node_counts(
sn, ind, r.
space[s].local[isf - 1]), counts))
182 for (std::size_t s = 0; s < r.
space.size(); ++s) {
184 for (std::size_t f = 0; f <
sn.stateful_nodes.size() && all; ++f)
185 if (!getters_detail::same_row(r.
space[s].local[f], st.
local[f])) all =
false;
197 const std::size_t NF =
sn.stateful_nodes.size();
198 std::vector<std::vector<double>> want(NF);
199 for (std::size_t f = 0; f < NF; ++f)
200 want[f] = getters_detail::node_counts(
sn,
sn.stateful_nodes[f], st.
local[f]);
202 for (std::size_t s = 0; s < r.
space.size(); ++s) {
204 for (std::size_t f = 0; f < NF && all; ++f)
205 if (!getters_detail::same_counts(
206 getters_detail::node_counts(
sn,
sn.stateful_nodes[f], r.
space[s].local[f]),
226 const std::size_t NF =
sn.stateful_nodes.size();
233 std::size_t width = 0;
234 for (std::size_t f = 0; f < NF; ++f)
235 width += r.
space.empty() ? 0 : r.
space[0].local[f].size();
239 for (std::size_t i = 0; i < n; ++i) {
242 for (std::size_t f = 0; f < NF; ++f)
243 for (std::size_t j = 0; j < r.
space[s].local[f].size(); ++j)
245 for (std::size_t c = 0; c < r.
ssq.cols(); ++c) out.
aggr(i, c) = r.
ssq(s, c);
261 const std::size_t isf =
sn.stateful_index(ind);
263 throw InputError(
"ssa_sample_node: node '" + getters_detail::node_label(
sn, ind) +
264 "' is stateless, so no trajectory passes through its state");
271 const std::size_t width = r.
space.empty() ? 0 : r.
space[0].local[isf - 1].size();
274 for (std::size_t i = 0; i < n; ++i) {
276 for (std::size_t j = 0; j < width; ++j) out.
state(i, j) = r.
space[s].local[isf - 1][j];
277 const std::vector<double> c = getters_detail::node_counts(
sn, ind, r.
space[s].local[isf - 1]);
278 for (std::size_t k = 0; k < c.size() && k <
sn.nclasses; ++k)
297 if (!
sim.fjclassmap.empty())
299 "SolverSSA: a probability query on a fork-join model would be asked in the CALLER's "
300 "class space and answered in the tag-augmented one, whose sibling classes the caller "
301 "never declared and cannot name a state in; SolverCTMC reports the same query on the "
302 "augmented chain, so use it, or ask for -a avg here");
308 serial_detail::wide_init_state(
sn, ctmc::analyzer_detail::resolve_cutoff(
sn, copt));
316 for (std::size_t i = 0; i <
sn.nstations; ++i) {
317 const std::size_t ind =
sn.node_of_station(i + 1);
318 const std::size_t isf =
sn.stateful_index(ind);
326 sn,
sim.run, ind, getters_detail::node_counts(
sn, ind, init.
local[isf - 1])));
343 "SolverSSA does not record per-job response times, so it cannot return an empirical "
344 "response time CDF; the inherited exponential fit would carry no information about the "
345 "tail while looking measured. Use SolverJMT for a measured CDF, SolverFluid or SolverMAM "
346 "for an analytical one");
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
The exception types the port throws.
Dense matrix and non-owning view.
std::pair< T, std::vector< T > > to_marginal_aggr(const NetworkStruct< T > &sn, std::size_t ind, const std::vector< T > &state_i)
Port of State.toMarginalAggr: the job counts of one node's state row, without the per-phase detail to...
SsaSerialSolution< T > solver_ssa_serial_analyzer(const qn::NetworkStruct< T > &sn, const SsaSerialOptions &opt)
Port of solver_ssa_analyzer_serial.m plus the fork-join wrapper @@SolverSSA/runAnalyzer....
SsaProbResult ssa_prob_aggr(const qn::NetworkStruct< T > &sn, const SsaSerialRun< T > &r, std::size_t ind, const std::vector< double > &counts)
getProbAggr(node, n): the same, over the per-class counts alone.
SsaProbReport solver_ssa_prob(const qn::NetworkStruct< T > &sn, const SsaSerialOptions &opt)
The whole -a prob report over the model's DEFAULT INITIAL STATE, which is the state SolverCTMC's own ...
SsaSamplePath< T > ssa_sample_node(const qn::NetworkStruct< T > &sn, const SsaSerialRun< T > &r, std::size_t ind)
sample(node) and sampleAggr(node): the same trajectory, one node's block.
SsaSamplePath< T > ssa_sample_sys(const qn::NetworkStruct< T > &sn, const SsaSerialRun< T > &r)
sampleSys and sampleSysAggr: the trajectory itself.
SsaProbResult ssa_prob_sys(const qn::NetworkStruct< T > &sn, const SsaSerialRun< T > &r, const qn::NetState< T > &st)
getProbSys(): the joint state of every stateful node at once.
SsaProbResult ssa_prob_sys_aggr(const qn::NetworkStruct< T > &sn, const SsaSerialRun< T > &r, const qn::NetState< T > &st)
getProbSysAggr(): the joint per-class counts of every stateful node.
void ssa_cdf_respt_refuse()
getCdfRespT: refused, and the refusal is the ANSWER rather than a gap.
SsaProbResult ssa_prob(const qn::NetworkStruct< T > &sn, const SsaSerialRun< T > &r, std::size_t ind, const std::vector< T > &row)
getProb(node, state): the time fraction the path spent with node ind in row.
A queueing network and its refreshed NetworkStruct.
Port of solver_ctmc_analyzer.m and the parts of @@SolverCTMC/runAnalyzer.m that surround one solve: t...
SolverSSA, the serial method: a port of solver_ssa_reachability.m, of the run loop of solver_ssa....
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 SolverCTMC knobs this port honours.
std::size_t state_max
refuse a space larger than this
double cutoff
< 0 = not given
One network state: the per-stateful-node local rows it is composed of.
std::vector< std::vector< T > > local
local[isf] is that node's state row
The four probabilities -a prob reports, over one requested state.
SsaProbResult sys_aggr
getProbSys, getProbSysAggr
std::vector< SsaProbResult > aggr
getProb, getProbAggr, per station
std::vector< SsaProbResult > marg
One probability query: the estimate, and whether the state occurred at all.
One trajectory, in the shape the reference's sampleSys returns it.
std::vector< double > t
the event times, increasing
Matrix< T > aggr
the same, as per-(stateful, class) counts
std::vector< std::size_t > event
which synchronization fired
Matrix< T > state
per event: the state OCCUPIED until then
The serial engine's knobs: SsaOptions plus the three the serial path reads and the NRM has no use for...
One sample path, in the shape solver_ssa.m returns it.
std::vector< qn::NetState< T > > space
The DISTINCT states visited, in first-visit order (the reference's u).
std::vector< double > tran_time
tranSysState{1}: the cumulative time at each firing.
std::vector< std::size_t > tran_state
The row of space the path OCCUPIED over [t-dt, t], one per firing.
Matrix< T > ssq
SSq: the per-(station, class) job counts of each distinct state.
unsigned long seed
the stream this path came from
std::size_t samples
firings actually performed
std::vector< double > pi
pi: the fraction of simulated time spent in each of them.
std::vector< std::size_t > tran_sync
tranSync: which synchronization fired, sync.size() + g for a global one.
The serial analyzer's return: the metric table, the path, and the stream.