![]() |
LINE Solver (C++)
Templated C++ port of the LINE queueing solver
|
SolverSSA on a STOCHASTIC PETRI NET: the port of solver_ssa_nrm_spn, the sub-engine solver_ssa_nrm.m:174 hands a net carrying Transition nodes to. More...
#include <algorithm>#include <cmath>#include <cstddef>#include <functional>#include <limits>#include <string>#include <vector>#include "line/api/sn/sn_fluid_refusal.h"#include "line/lang/qn/network_struct.h"#include "line/solvers/ssa/ssa_types.h"#include "line/util/error.h"#include "line/util/line_console.h"#include "line/util/matrix.h"#include "line/util/rootfind.h"Go to the source code of this file.
Classes | |
| class | line::ssa::NrmSpnEngine< T > |
| The SPN Next-Reaction-Method engine, solver_ssa_nrm_spn of the reference. More... | |
Namespaces | |
| namespace | line |
| Conservation laws of a layered queueing network, enumerated from its structure. | |
| namespace | line::ssa |
SolverSSA on a STOCHASTIC PETRI NET: the port of solver_ssa_nrm_spn, the sub-engine solver_ssa_nrm.m:174 hands a net carrying Transition nodes to.
WHY IT IS A SEPARATE ENGINE. The queueing reaction builder of solver_ssa_nrm.h reads a state vector of JOBS PER (node, class, phase) and a departure is the absorption of a service process. A Petri net has neither: a Place holds TOKENS, a Transition mode is a reaction whose stoichiometry is the arc incidence, and nothing in the net has a service phase. The reference therefore branches on any(sn.nodetype == NodeType.Transition) before it builds a single reaction, and so does this port.
THE MAPPING IS EXACT, not an approximation. A Place holds a per-class token count (one slot of the state vector), and a timed Transition mode is a reaction: input (enabling) arcs consume, output (firing) arcs produce. Enabling is a propensity gate – every input place at or above its arc weight, every inhibitor place strictly below its threshold – and a single-server mode fires at its exponential rate while an infinite or k-server mode fires at that rate times its enabling degree. One firing applies the stoichiometry once, which is the atomic GSPN firing the exact CTMC, JMT and the standard GSPN tools all take.
IMMEDIATE MODES ARE NOT REACTIONS. They fire in zero time, so they are resolved by VANISHING-MARKING ELIMINATION: after every timed firing (and once on the initial marking) every enabled immediate mode is fired – highest firing priority first and, among equal priority, drawn in proportion to firing weight – until the marking is tangible. The timed race therefore only ever samples from tangible markings and the immediate modes consume no simulated time.
A SOURCE IS NOT A TRANSITION and needs a reaction of its own, or the Place it feeds stays empty and the net deadlocks on the first draw. Splitting a Poisson stream by independent routing probabilities yields independent Poisson streams, so the edge of probability p carries rate lambda*p exactly; the reaction has an EMPTY enabling set (a constant propensity) and deposits one token into the routed Place slot.
WHAT IT REFUSES, and each refusal is the reference's: a non-exponential timed firing (representing an in-flight firing's phase would need per-mode phase state the reaction network does not carry), a non-exponential Source arrival into a Place, a Source that reaches no Place, an infinite initial marking, and a marking-dependent firing rate – the last under EVERY SSA method, since no SSA engine applies the g(marking) multiplier and answering with the nominal rate would be silently wrong. spn_nrm_supported is the predicate; the default dispatch reads it to decide whether to prefer this engine, and the explicit nrm arm reads it to refuse by name.
THE SLOT LAYOUT IS FLAT, one slot per (node, class), where the queueing engine's is per (node, class, PHASE). Nothing here has a phase: a Place holds tokens rather than jobs in service, and the reference's own SPN path only ever addresses phOff(place, class) + 1, the first phase slot of the pair. The two layouts therefore agree on every slot this engine touches.
NOT A SAMPLE-PATH TWIN OF THE REFERENCE. The random stream is this port's MT19937 (SsaRng) and the draw order is the algorithm's, so a seeded run matches the reference STATISTICALLY and never bit for bit, exactly as the queueing NRM does.
A FLUID NET (FSPN, Place::set_fluid) runs a PIECEWISE-DETERMINISTIC loop instead, the reference's spnFluidRun. Between two firings the marking is constant, so every fluid level moves LINEARLY at the slope its running flows give it: a flow of a timed mode counts once per running server, min(enabling degree, servers), and only while every guard of the mode holds. Three things end a segment and the first one wins: a FIRING (a Gibson-Bruck clock runs out; a mode whose rate depends on a level has a hazard that varies along the segment, so its clock is integrated by adaptive quadrature and the epoch is a root of the cumulative hazard), a GUARD crossing (nothing fires; the guards are re-read and the immediate modes the crossing enabled fire in zero time), or a BOUND hit at 0 or the capacity (nothing fires; the slope that would carry the level out is cut from then on). A firing applies the token stoichiometry and then the mode's IMPULSES, each clipped at the bounds. A guard is inclusive and read with a LOOKAHEAD at the threshold: it holds there only if the slope keeps it holding, and a guarded flow that pushes its own level back across its own guard (a sliding mode) is refused by name. A fluid place reports its time-average level as QN and everything that leaves it as TN. ssa_fluid_refusal is the gate: a fluid net has this one engine, so serial is refused.
Definition in file solver_ssa_nrm_spn.h.