LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
ssa_mlmc_network.h
Go to the documentation of this file.
1#ifndef LINE_SOLVERS_SSA_MLMC_NETWORK_H
2#define LINE_SOLVERS_SSA_MLMC_NETWORK_H
8
9namespace line { namespace ssa {
10/** The MLMC envelope, single-sourced in solver_feature_sets.h so the supports path and this run-time gate agree. */
14 std::vector<std::string> names;
15};
16/** Compile fixed routed channels, retaining all station/class dimensions. */
17inline MlmcCompiled ssa_mlmc_problem(const qn::NetworkStruct<double>& sn,const std::string& rewardName="") {
19 if(!support.ok) throw qn::feature_refusal(support);
20 using NT=lang::NodeType; using SS=lang::SchedStrategy;
21 const std::size_t M=sn.stations.size(),R=sn.nclasses;
22 for(const auto& s:sn.stations) if(R>1&&s.sched==SS::FCFS)
23 throw UnsupportedError(ErrorKind{"MultiClass"}, "SSA MLMC requires a population state; multiclass FCFS needs queue order");
24 for(const auto& s:sn.statespace) if(s.second.rows()!=1)
25 throw UnsupportedError(ErrorKind{"Model"}, "MLMC requires a deterministic initial state");
27 if(!ctmc::analyzer_detail::default_init_state(sn,init)) throw InputError("Invalid MLMC initial state");
28 std::vector<std::size_t> retained,keep,routeIndex(sn.nodes.size());
29 for(std::size_t node=0;node<sn.nodes.size();++node) if(sn.nodes[node].station!=0||sn.nodes[node].nodetype==NT::Sink) {
30 routeIndex[node]=retained.size(); retained.push_back(node);
31 for(std::size_t r=0;r<R;++r) keep.push_back(node*R+r);
32 }
33 auto routing=mc::dtmc_stochcomp(sn.rtnodes,keep);
34 MlmcCompiled out; auto& p=out.problem;
35 p.x0.assign(M*R,0); p.nu.resize(M*R);
36 std::vector<std::size_t> origins;
37 std::vector<double> weights,servers(M);
38 std::vector<SS> sched(M); std::vector<bool> source(M);
39 std::vector<std::vector<double>> mu(M,std::vector<double>(R));
40 for(std::size_t i=0;i<M;++i) {
41 std::size_t node=sn.station_to_node[i]; source[i]=sn.nodes[node-1].nodetype==NT::Source;
42 sched[i]=sn.stations[i].sched; servers[i]=sn.stations[i].nservers;
43 if(!source[i]) {
44 auto a=qn::to_marginal_aggr(sn,node,init.local[sn.stateful_index(node)-1]);
45 for(std::size_t r=0;r<R;++r) p.x0[i*R+r]=a.second[r];
46 }
47 for(std::size_t r=0;r<R;++r) {
48 double rate=sn.rates(i,r); mu[i][r]=std::isnan(rate)?0:rate;
49 if(mu[i][r]==0) continue;
50 if(!std::isfinite(rate)||rate<0) throw InputError("MLMC requires finite exponential rates");
51 double total=0;
52 for(std::size_t dest=0;dest<retained.size()*R;++dest) {
53 double w=routing(routeIndex[node-1]*R+r,dest);
54 if(!std::isfinite(w)||w<0) throw InputError("Invalid MLMC routing probability");
55 total+=w; if(w==0) continue;
56 std::size_t j=retained[dest/R],s=dest%R;
57 std::vector<double> change(M*R,0);
58 if(!source[i]) change[i*R+r]--;
59 if(sn.nodes[j].nodetype!=NT::Sink) {
60 if(sn.nodes[j].nodetype==NT::Source||sn.nodes[j].station==0)
61 throw UnsupportedError(ErrorKind{"Topology"}, "MLMC routes directly to queues, delays or sinks");
62 change[(sn.nodes[j].station-1)*R+s]++;
63 }
64 for(std::size_t a=0;a<M*R;++a) p.nu[a].push_back(change[a]);
65 origins.push_back(i*R+r); weights.push_back(w);
66 }
67 if(std::abs(total-1)>1e-10) throw InputError("Active station/class routing must sum to one");
68 }
69 }
70 std::vector<qn::NetworkStruct<double>::Reward> rewards;
71 for(const auto& r:sn.reward) if(rewardName.empty()||r.name==rewardName) {
72 out.names.push_back(r.name); rewards.push_back(r);
73 }
74 if(!rewardName.empty()&&rewards.empty()) throw InputError("Unknown reward: "+rewardName);
75 p.rates=[=](const std::vector<double>& x) {
76 std::vector<double> d(M*R,0);
77 for(std::size_t i=0;i<M;++i) {
78 double n=0; for(std::size_t r=0;r<R;++r) n+=std::max(x[i*R+r],0.0);
79 for(std::size_t r=0;r<R;++r) {
80 if(source[i]) d[i*R+r]=mu[i][r];
81 else if(sched[i]==SS::INF) d[i*R+r]=mu[i][r]*std::max(x[i*R+r],0.0);
82 else if(n>0) d[i*R+r]=mu[i][r]*std::max(x[i*R+r],0.0)*std::min(n,servers[i])/n;
83 }
84 }
85 std::vector<double> a(origins.size());
86 for(std::size_t k=0;k<a.size();++k) a[k]=d[origins[k]]*weights[k];
87 return a;
88 };
89 p.observe=[rewards](const std::vector<double>& x) {
90 std::vector<double> f; for(const auto& r:rewards) f.push_back(r.fn(x)); return f;
91 };
92 return out;
93}
94
95/** SSA's finite-horizon reward getter. The usual average analyzer refuses MLMC. */
96inline std::vector<MlmcResult> solver_ssa_get_tran_reward(const qn::NetworkStruct<double>& sn,
97 const SsaOptions& opt,const std::vector<double>& times,const std::string& name="",
98 const MlmcOptions& control=MlmcOptions()) {
99 if(opt.method!="mlmc") throw InputError("getTranReward requires SSA method mlmc");
100 if(times.empty()) throw InputError("Observation times must be nonempty");
101 auto compiled=ssa_mlmc_problem(sn,name);
102 std::vector<MlmcResult> out;
103 for(double t:times) {
104 auto runControl=control; runControl.seed=opt.seed;
105 auto result=ssa_mlmc(compiled.problem,t,runControl);
106 result.names=compiled.names; result.method=opt.method; out.push_back(result);
107 }
108 return out;
109}
110}} // line::ssa
111#endif
InputError(const std::string &what)
Definition error.h:105
UnsupportedError(const std::string &what)
Definition error.h:119
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.
SchedStrategy
Scheduling disciplines, with the values of MATLAB SchedStrategy.
Definition lang_types.h:185
NodeType
Node kinds, with the values of MATLAB NodeType.
Definition lang_types.h:331
Matrix< T > dtmc_stochcomp(const Matrix< T > &P, const std::vector< std::size_t > &keep)
Stochastic complement of a DTMC partition, a port of matlab/lib/kpctoolbox/mc/dtmc_stochcomp....
FeatureSet used_lang_features(const NetworkStruct< T > &sn)
UnsupportedError feature_refusal(const SupportResult &r)
The refusal a failed gate raises: LINE:unsupported:<kind>, where the kind is the FIRST missing featur...
SupportResult feature_set_supports(const std::string &solver, const FeatureSet &declared, const FeatureSet &used)
SolverFeatureSet.supports: is every feature the model uses declared?
FeatureSet ssa_mlmc_feature_set()
SolverSSA.getFeatureSet, 98 MATLAB names.
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...
MlmcResult ssa_mlmc(const MlmcProblem &p, double time, const MlmcOptions &o=MlmcOptions())
Independent pilots, fixed production counts, pointwise normal intervals.
Definition ssa_mlmc.h:221
std::vector< MlmcResult > solver_ssa_get_tran_reward(const qn::NetworkStruct< double > &sn, const SsaOptions &opt, const std::vector< double > &times, const std::string &name="", const MlmcOptions &control=MlmcOptions())
SSA's finite-horizon reward getter.
MlmcCompiled ssa_mlmc_problem(const qn::NetworkStruct< double > &sn, const std::string &rewardName="")
Compile fixed routed channels, retaining all station/class dimensions.
qn::FeatureSet mlmc_feature_set()
The MLMC envelope, single-sourced in solver_feature_sets.h so the supports path and this run-time gat...
Conservation laws of a layered queueing network, enumerated from its structure.
Definition aoi_dist2ph.h:52
Port of solver_ctmc_analyzer.m and the parts of @@SolverCTMC/runAnalyzer.m that surround one solve: t...
The DECLARED side of the gate: one feature set per solver.
Controls, results and the random source of SolverSSA.
The <kind> part of a LINE:<category>:<kind> identifier (see _kb/17-error-vocabulary....
Definition error.h:37
One network state: the per-stateful-node local rows it is composed of.
Definition state.h:2734
std::vector< std::string > names
Generic fixed-increment jump process.
Definition ssa_mlmc.h:18
std::vector< double > x0
Definition ssa_mlmc.h:19
Controls, defaulting to SolverOptions('SSA') in the reference.
Definition ssa_types.h:71