![]() |
LINE Solver (C++)
Templated C++ port of the LINE queueing solver
|
The SolverSSA entry surface: a port of @@SolverSSA/runAnalyzer.m's method whitelist, of solver_ssa_analyzer.m's eligibility gate (isNrmEligible and the per-feature *NrmOK predicates) and of solver_ssa_analyzer_nrm.m's own scheduling validation. More...
#include <algorithm>#include <cmath>#include <string>#include <vector>#include "line/api/sn/sn_pn_firing_rates.h"#include "line/lang/qn/network_struct.h"#include "line/solvers/cache_metrics.h"#include "line/solvers/ssa/solver_ssa_nrm.h"#include "line/solvers/ssa/solver_ssa_nrm_space.h"#include "line/solvers/ssa/solver_ssa_nrm_spn.h"#include "line/solvers/ssa/solver_ssa_parallel.h"#include "line/solvers/ssa/solver_ssa_serial.h"#include "line/solvers/ssa/ssa_types.h"#include "line/solvers/ssa/ssa_mlmc_network.h"#include "line/util/error.h"#include "line/solvers/method_registry.h"#include "line/solvers/mva/solver_mva_runner.h"Go to the source code of this file.
Namespaces | |
| namespace | line |
| Conservation laws of a layered queueing network, enumerated from its structure. | |
| namespace | line::ssa |
Functions | |
| std::vector< std::string > | line::ssa::list_valid_methods () |
| Port of SolverSSA.listValidMethods. | |
| template<class T> | |
| SsaSolution | line::ssa::solver_ssa_nrm_analyzer (const qn::NetworkStruct< T > &sn, const SsaOptions &opt, std::vector< SsaCacheRatio > *cache=nullptr) |
| solver_ssa_analyzer_nrm.m: run the NRM and return the metric table. | |
| template<class T> | |
| SsaSolution | line::ssa::solver_ssa_engine (const qn::NetworkStruct< T > &sn, const SsaOptions &opt_in, std::vector< SsaCacheRatio > *cache) |
| solver_ssa_analyzer.m: choose the method. | |
| template<class T> | |
| qn::NetworkStruct< T > | line::ssa::sn_with_ssa_cache_split (const qn::NetworkStruct< T > &base, const std::vector< SsaCacheRatio > &cache) |
| @@SolverSSA/runAnalyzer itself: the engine the method selects, then the result assembly the reference does before it hands the table to a caller. | |
| template<class T> | |
| SsaSolution | line::ssa::ssa_imm_tput_balance (const qn::NetworkStruct< T > &sn, const SsaSolution &in) |
| Port of ssa_imm_tput_balance.m: the throughput of every station-class pair whose service is Immediate, taken from flow balance rather than from the sample path. | |
| template<class T> | |
| SsaSolution | line::ssa::solver_ssa (const qn::NetworkStruct< T > &sn, const SsaOptions &opt, std::vector< SsaCacheRatio > *cache=nullptr) |
| template<class T> | |
| solvers::CacheMetrics< T > | line::ssa::cache_metrics_of_ssa (const qn::NetworkStruct< T > &sn, const std::vector< SsaCacheRatio > &cache) |
| CacheMetrics from the serial engine's cache write-back. | |
The SolverSSA entry surface: a port of @@SolverSSA/runAnalyzer.m's method whitelist, of solver_ssa_analyzer.m's eligibility gate (isNrmEligible and the per-feature *NrmOK predicates) and of solver_ssa_analyzer_nrm.m's own scheduling validation.
EVERY METHOD THE REFERENCE OFFERS IS REACHED FROM HERE. SolverSSA.m line 55 lists default, ssa, serial, para/parallel and nrm; the JAR's SolverSSA.listValidMethods and native Python's list the same set. All five resolve to one of the three ported engines: the NRM of solver_ssa_nrm.h, the event-driven engine of solver_ssa_serial.h, and the replica mean of solver_ssa_parallel.h. para/parallel prefers the NRM whenever the model is eligible and replicates the serial engine otherwise, exactly as the reference does; ssa is the reference's alias for serial, NOT for the NRM; default is the reference's ladder – the NRM when eligible, the serial engine otherwise – as solver_ssa sets out below. solver_ssa returns the metric table alone, so a caller who needs the sample path, the per-replica tables or their standard errors calls the engine's own entry. The mlmc method uses the dedicated finite-horizon solver_ssa_get_tran_reward getter; the metric analyzer refuses them.
WITHIN nrm THERE ARE TWO ENGINES, and both are reached from here. The reference picks between them on options.config.state_space_gen (solver_ssa_analyzer_nrm.m lines 52-68): none and default take the plain engine of solver_ssa_nrm.m, which integrates the metrics along the sample path, and any other value takes the tabulating engine of solver_ssa_nrm_space.m, which records the distinct states visited and forms the means as pi * A. SsaOptions::state_space_gen is that switch, and the eligibility gate below runs before it, exactly as the reference's does: it is the NRM's gate, not one engine's. The space engine then applies its OWN further refusals (an open model, a phase-type service, a space above the cap), each by name, in NrmSpaceEngine::check.
WHY THE GATE IS SO LONG, AND WHAT IT IS FOR. It is isNrmEligible (solver_ssa_analyzer.m lines 365-386) and it answers ONE question: can the NRM run this model? Under method='nrm' a no is a refusal BY NAME, because a caller who spelled out the estimator asked for that estimator; under default and parallel the same no is a fallback to the serial engine, as the reference's is. The two share a body (raise), so they cannot drift.
WHAT THE GATE MEANS SINCE THE FALLBACK WAS RESTORED. It is the NRM's reach and NOT SolverSSA's: everything it rejects, the serial engine runs (a Fork, a BLOCKING region rule, global dependence), so a rejection under default costs the caller the NRM's SPEED and not the answer. Under method='nrm' it is still a refusal by name, because an estimator that was asked for by name must be the one that runs. What the NRM lacks falls in two groups:
NOT REPRESENTABLE the struct has no field at all, so a model using the feature cannot be built (SelfLoopingClass – JobClassType is OPEN or CLOSED only). RROBIN, WRROBIN, JSQ and SQ are NOT here: the NRM resolves all four at firing time (resolve_state_dependent_dest). REFUSED IN EVERY CODEBASE'S NRM Fork/Join, the blocking region rules BAS / BBS / RSRD, and global (Whittle) dependence; the reference's isNrmEligible excludes the same set. Reneging, balking and retrial orbits are refused by ssa_check_impatience, and G-network signals (issignal and friends) downstream, by the engines that would have to simulate them.
The sub-engines that have LEFT the refusal list, all in solver_ssa_nrm.h unless named: the *PRIO shares on 2026-08-15; the stochastic Petri net path on 2026-09-13 (solver_ssa_nrm_spn.h, which still refuses the four firing laws spn_nrm_supported names); and on 2026-09-24 class- and joint-dependent scaling (cdfac), finite capacity regions under DROP and WAITQ (fcr_outcome / fcr_release_cascade), PAS / OI (pas_rate / pas_depart), POLLING (PollCtrl and one switchover reaction per station) and the Cache (cache_fire, drawing each READ from after_event_cache). The tabulating engine of solver_ssa_nrm_space.h does not carry those five and refuses them itself, by name.
Nothing falls through silently: a model with a construct the reaction table does not model would run to completion and return numbers that are simply not the model's, which is why the gate stays even where the serial engine can answer.
Definition in file ssa_dispatch.h.