![]() |
LINE Solver (C++)
Templated C++ port of the LINE queueing solver
|
SolverSSA, the serial method: a port of solver_ssa_reachability.m, of the run loop of solver_ssa.m, and of solver_ssa_analyzer_serial.m. More...
#include <algorithm>#include <cmath>#include <cstddef>#include <limits>#include <map>#include <string>#include <type_traits>#include <vector>#include "line/api/mam/map_moment.h"#include "line/lang/qn/fj_tag.h"#include "line/solvers/tr/fj_tag_transform.h"#include "line/lang/qn/network_struct.h"#include "line/lang/qn/state.h"#include "line/lang/qn/state_events.h"#include "line/solvers/ctmc/solver_ctmc.h"#include "line/solvers/ctmc/solver_ctmc_analyzer.h"#include "line/solvers/ctmc/solver_ctmc_fcr.h"#include "line/solvers/ctmc/solver_ctmc_waitq.h"#include "line/solvers/ssa/ssa_types.h"#include "line/util/error.h"#include "line/util/matrix.h"Go to the source code of this file.
Classes | |
| struct | line::ssa::SsaSerialOptions |
| The serial engine's knobs: SsaOptions plus the three the serial path reads and the NRM has no use for. More... | |
| struct | line::ssa::SsaReachability< T > |
| Port of solver_ssa_reachability.m's return: [SSq, SSh, sn.space]. More... | |
| struct | line::ssa::SsaSerialRun< T > |
| One sample path, in the shape solver_ssa.m returns it. More... | |
| struct | line::ssa::SsaCacheRatio |
| What the cache write-back of solver_ssa_analyzer_serial.m produces. More... | |
| struct | line::ssa::SsaSerialSolution< T > |
| The serial analyzer's return: the metric table, the path, and the stream. More... | |
| class | line::ssa::SsaSerialEngine< T > |
| The serial engine: the sample path of solver_ssa.m's main loop. More... | |
Namespaces | |
| namespace | line |
| namespace | line::ssa |
Functions | |
| template<class T> | |
| SsaReachability< T > | line::ssa::solver_ssa_reachability (const qn::NetworkStruct< T > &sn, const SsaSerialOptions &opt=SsaSerialOptions()) |
| Port of solver_ssa_reachability.m: the states the DYNAMICS can occupy, decomposed per stateful node. | |
| template<class T> | |
| SsaSerialSolution< T > | line::ssa::solver_ssa_serial_on_struct (const qn::NetworkStruct< T > &sn, const SsaSerialOptions &opt, const std::vector< qn::FjSync< T > > &fjsync) |
| Port of solver_ssa_analyzer_serial.m: run the serial engine and reduce its path to the metric table. | |
| template<class T> | |
| SsaSerialSolution< T > | line::ssa::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.m puts in front of it. | |
| template<class T> | |
| SsaSerialSolution< T > | line::ssa::solver_ssa_serial (const qn::NetworkStruct< T > &sn, const SsaSerialOptions &opt) |
| The serial entry of solver_ssa_analyzer.m. | |
SolverSSA, the serial method: a port of solver_ssa_reachability.m, of the run loop of solver_ssa.m, and of solver_ssa_analyzer_serial.m.
WHAT THE METHOD IS, AND HOW IT DIFFERS FROM THE NRM. The NRM rewrites the network as a reaction grid over (node, class, phase) counts and never touches the state ENCODING. The serial engine simulates the network in its own encoding instead: at every step it applies the SAME event handlers the CTMC generator applies (after_event, after_global_event) to the current network state, collects every enabled synchronization with its rate, and takes one Gillespie direct-method step. That is why it reaches models the NRM refuses – anything the encoding can express, the handlers can move – and why it is slower: the enabled set is rebuilt from scratch at every firing, as the reference's own inlined solver_ssa_findenabled does.
TWO ENGINES, TWO STREAMS. A seed-fixed result from the serial engine cannot be reproduced by the NRM and vice versa: they consume different draws in a different order. Neither can be reproduced by MATLAB, the JAR or native Python, for the reason ssa_types.h states at length. A cross-codebase check against this engine is STATISTICAL. A simulated number without its sample count and its seed is not a measurement, which is why SsaSerialSolution carries both and why the tests compare against the exact CTMC only inside a stated Monte Carlo band.
THE JUMP CHAIN IS DRAWN IN ONE STEP, NOT TWO. MATLAB calls State.afterEvent with isSimulation = true, which SAMPLES one successor row and returns its probability; the direct method then picks among the sampled rows. The C++ after_event is the enumeration-mode handler and returns EVERY successor with its probability, so this port flattens the (synchronization, active row, passive row) triples into one weighted list and draws from it once. The two are the same jump chain – P(triple) = rate * p_active * p_route * p_passive, normalized – reached with a different number of uniforms, which is exactly the stream difference above and not a modelling difference.
ZERO-RATE ROWS ARE DROPPED, NOT FLOORED. The reference rewrites a zero or NaN rate to 1e-38 "so that it is never selected", which leaves it in the enabled list and in the arrival/departure rate statistics. Dropping it is the same sample path to within 1e-38 and keeps depRates exactly the rate the CTMC generator would accumulate for the same state, which is what makes the throughput comparable between the two solvers.
THE STATE ROW DOES NOT GROW HERE, SO IT STARTS WIDE. MATLAB's simulation-mode handlers widen a buffer when a job arrives and no slot is free, and solver_ssa_reachability left-pads the stored spaces to match. The C++ handlers derive the buffer width from the row they are handed, so a path seeded at the natural width of the EMPTY marginal would silently saturate at one waiting job per station. The initial state is therefore padded to the WIDEST row each stateful node's local encoding admits (serial_detail:: max_row_width), which is the width space_generator gives every state of that node, and the path then lives inside the enumerated encoding for free.
DOUBLE ONLY, for the reason solver_ssa_nrm.h gives: the sample path is generated from exponential clocks drawn as -log(u), there is no exact value to compute, and the answer's error is the Monte Carlo error rather than the rounding. A non-double backend is refused BY NAME.
Definition in file solver_ssa_serial.h.