LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
map_env_gate.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_SOLVERS_MAP_ENV_GATE_H
6#define LINE_SOLVERS_MAP_ENV_GATE_H
7
8/**
9 * @file
10 * @ingroup line_solvers
11 * The map_env decision, as a predicate over a feature set.
12 *
13 * WHAT IT DECIDES. `@NetworkSolver/needsMapEnv.m` asks one question: are the
14 * ONLY features this solver cannot consume non-renewal arrival or service
15 * processes? If so the model becomes supported the moment each modulated
16 * process is frozen into an exponential environment stage, and `map2renv` plus
17 * SolverENV can answer it. If anything else is unsupported the environment
18 * image would not make the model solvable, so the original refusal stands and
19 * is raised by the runner in its own words.
20 *
21 * WHY IT IS ITS OWN HEADER, and a small one. Two callers need it and they sit
22 * at opposite ends of the include graph: the driver in `map_env.h`, which pulls
23 * in `env/` and therefore everything below it, and the AUTO / `find_solver`
24 * reporting layer, which only wants to know whether a solver would answer. This
25 * header depends on `lang/qn/feature_set.h` alone, so the reporting layer can
26 * ask the question without linking a single solver.
27 *
28 * THE FOUR NAMES ARE THE REFERENCE'S OWN `mapTokens` and are a closed list:
29 * MAP, MMPP2, MMAP and MPH. DMAP, BMAP, MAPt, PHt, MMAPt, MPHt and BMMAPt are
30 * deliberately NOT here. `map2renv` freezes a stationary, continuous-time,
31 * single-arrival modulating chain into one exponential stage per phase; a
32 * discrete-time chain has no such stage, a batch process releases more than one
33 * job per epoch and so is not described by a rate, and a time-inhomogeneous one
34 * has no stationary phase to freeze at all. Adding a name here without adding
35 * the transform would send a model into an image that does not represent it.
36 */
37
38#include <string>
39#include <vector>
40
42
43namespace line {
44namespace solvers {
45
46/**
47 * The caller-facing map_env knobs, `options.config.map_env` and friends.
48 *
49 * `mode` is `"default"` (fall back when the gate says so) or `"off"` (keep the
50 * plain rejection). `method` is the SolverENV coupling the driver asks for,
51 * with `"auto"` choosing between the mean-field one and the closed-form limits
52 * the way `selectEnvLimit` does. `max_stages` caps how many stages the image
53 * may have, since one stage per modulating phase of every non-renewal process
54 * is a product and can be large.
55 */
57 std::string mode = "default";
58 std::string method = "auto";
59 std::size_t max_stages = 0; ///< 0 = the transform's own default cap
60 bool off() const { return mode == "off"; }
61};
62
63/** The four process names an environment image can represent; the order is the registry's. */
64inline const std::vector<qn::Feature>& map_env_tokens() {
65 static const std::vector<qn::Feature> t = {qn::Feature::MAP, qn::Feature::MMAP,
66 qn::Feature::MMPP2, qn::Feature::MPH};
67 return t;
68}
69
70/** True when `f` is one of the four. */
72 const std::vector<qn::Feature>& t = map_env_tokens();
73 for (std::size_t i = 0; i < t.size(); ++i)
74 if (t[i] == f) return true;
75 return false;
76}
77
78/** What the gate decided, and what it decided it about. */
80 bool needed = false;
81 /** The unsupported features, in registry order; all four-token when `needed`. */
82 std::vector<qn::Feature> tokens;
83 /** Those names, comma-separated, for a message. */
84 std::string token_names() const {
85 std::string s;
86 for (std::size_t i = 0; i < tokens.size(); ++i) {
87 if (i) s += ", ";
88 s += qn::feature_name(tokens[i]);
89 }
90 return s;
91 }
92};
93
94/**
95 * `needsMapEnv`: does this model need the environment image, and would the image
96 * make it solvable?
97 *
98 * `declared` is the feature set of the RESOLVED method, not of the solver: MVA's
99 * `default` upgrades to `rqna` on a bursty open model and rqna declares MAP, so
100 * asking the base envelope would send a model into an image the run did not need.
101 * The callers resolve the method first for exactly that reason.
102 *
103 * FALSE FOR A SUPPORTED MODEL, which is not the same as "no MAP in the model":
104 * a solver that declares the process consumes it natively and must not be
105 * diverted through an approximation of it.
106 */
107template <class T>
109 const MapEnvConfig& cfg = MapEnvConfig()) {
111 if (cfg.off()) return d;
112 const qn::SupportResult r =
113 qn::feature_set_supports("SolverENV", declared, qn::used_lang_features(sn));
114 if (r.ok || r.missing.empty()) return d;
115 for (std::size_t i = 0; i < r.missing.size(); ++i)
116 if (!is_map_env_token(r.missing[i])) return d;
117 d.needed = true;
118 d.tokens = r.missing;
119 return d;
120}
121
122/**
123 * Which ENV stage backend a solver's name maps to, or empty when it has none.
124 *
125 * NOT THE SAME QUESTION AS `supports_transient_analysis`. `SolverEnv::init`
126 * admits `stage_solver` in {fluid, ctmc} only, so LDES and JMT answer the
127 * transient capability TRUE and still have no backend in this port; asking the
128 * capability alone would pick the mean-field coupling for a solver that cannot
129 * run a stage, and the coupling would then refuse by name. Keyed on the label
130 * string the feature gate already takes ("SolverMVA", "SolverNC", ...), because
131 * that is the only solver identity that exists at this level.
132 */
133inline std::string map_env_stage_backend(const std::string& solver) {
134 if (solver == "SolverFLD" || solver == "SolverFluid") return "fluid";
135 if (solver == "SolverCTMC") return "ctmc";
136 return std::string();
137}
138
139/**
140 * `supportsTransientAnalysis`: does this solver produce transient averages?
141 *
142 * A CAPABILITY CLAIM, answered before any run, because the driver reads it to
143 * decide whether the stages can be coupled by the mean-field analyzer (which
144 * integrates each stage over its sojourn and so needs a transient) or only by
145 * the two steady-state limits. The four that populate `result.Tran.Avg` in the
146 * reference are FLD, CTMC, LDES and JMT.
147 */
148inline bool supports_transient_analysis(const std::string& solver) {
149 return solver == "SolverFLD" || solver == "SolverFluid" || solver == "SolverCTMC" ||
150 solver == "SolverLDES" || solver == "SolverJMT";
151}
152
153} // namespace solvers
154} // namespace line
155
156#endif // LINE_SOLVERS_MAP_ENV_GATE_H
A subset of the registry: MATLAB's SolverFeatureSet, whose list is a flag per field.
A network plus its refreshed NetworkStruct.
The language-feature gate: what a MODEL uses against what a SOLVER declares.
FeatureSet used_lang_features(const NetworkStruct< T > &sn)
Feature
One language feature.
SupportResult feature_set_supports(const std::string &solver, const FeatureSet &declared, const FeatureSet &used)
SolverFeatureSet.supports: is every feature the model uses declared?
const char * feature_name(Feature f)
The canonical registry name, byte for byte the MATLAB field name.
MapEnvDecision needs_map_env(const qn::FeatureSet &declared, const qn::NetworkStruct< T > &sn, const MapEnvConfig &cfg=MapEnvConfig())
needsMapEnv: does this model need the environment image, and would the image make it solvable?
bool is_map_env_token(qn::Feature f)
True when f is one of the four.
std::string map_env_stage_backend(const std::string &solver)
Which ENV stage backend a solver's name maps to, or empty when it has none.
const std::vector< qn::Feature > & map_env_tokens()
The four process names an environment image can represent; the order is the registry's.
bool supports_transient_analysis(const std::string &solver)
supportsTransientAnalysis: does this solver produce transient averages?
Conservation laws of a layered queueing network, enumerated from its structure.
Definition aoi_dist2ph.h:52
The outcome of the gate: the verdict, the offending features, the message.
std::vector< Feature > missing
used but not declared, in registry order
The caller-facing map_env knobs, options.config.map_env and friends.
std::size_t max_stages
0 = the transform's own default cap
What the gate decided, and what it decided it about.
std::vector< qn::Feature > tokens
The unsupported features, in registry order; all four-token when needed.
std::string token_names() const
Those names, comma-separated, for a message.