5#ifndef LINE_SOLVERS_FLUID_PETRI_TERMS_H
6#define LINE_SOLVERS_FLUID_PETRI_TERMS_H
100 std::vector<double>
d1;
128 std::vector<std::function<double(
double)>>
fdep_fun;
151 std::vector<std::ptrdiff_t>
fidx;
158 std::vector<std::vector<std::ptrdiff_t>>
pidx;
177 std::vector<std::pair<std::size_t, std::size_t>>
cov_pairs;
186 std::vector<double>
x0;
190namespace terms_detail {
194inline std::vector<std::vector<double>> pad(
const Matrix<T>& A, std::size_t I, std::size_t K,
196 std::vector<std::vector<double>> out(I, std::vector<double>(K, fill));
197 for (std::size_t i = 0; i < I && i < A.
rows(); ++i)
198 for (std::size_t k = 0; k < K && k < A.
cols(); ++k)
204inline void add_pair(std::map<std::pair<std::size_t, std::size_t>, std::size_t>& key,
205 std::vector<std::pair<std::size_t, std::size_t>>& pairs, std::size_t a,
207 const std::pair<std::size_t, std::size_t> k(std::min(a, b), std::max(a, b));
208 if (key.find(k) != key.end())
return;
209 key[k] = pairs.size();
221 std::size_t ind, std::size_t m, PetriTerms& t, std::size_t nm) {
228 : (
"Mode" + std::to_string(m + 1));
229 rec.label = t.names_node[ind - 1] +
"." + mname;
231 const std::vector<std::vector<double>> en = pad(tp.
enabling[m], t.I, t.K, 0.0);
232 const std::vector<std::vector<double>> fir = pad(tp.
firing[m], t.I, t.K, 0.0);
233 const std::vector<std::vector<double>> inh =
234 pad(tp.
inhibiting[m], t.I, t.K, std::numeric_limits<double>::infinity());
236 std::vector<double> cvec(nm, 0.0);
237 for (std::size_t p = 0; p < t.I; ++p)
238 for (std::size_t k = 0; k < t.K; ++k) {
239 const double w = en[p][k];
240 if (!(w > 0))
continue;
242 throw InputError(
"fluid_petri_terms: mode " + rec.label +
243 " has a non-finite enabling arc weight at " + t.names_node[p] +
244 ". An arc that no marking can satisfy disables the mode; declare "
245 "a finite multiplicity");
246 if (t.pidx[p][k] < 0)
247 throw InputError(
"fluid_petri_terms: mode " + rec.label +
248 " takes an enabling arc from " + t.names_node[p] +
249 ", which is not a Place");
250 const std::size_t s =
static_cast<std::size_t
>(t.pidx[p][k]);
251 rec.arc_slot.push_back(s);
252 rec.arc_w.push_back(w);
255 for (std::size_t p = 0; p < t.I; ++p)
256 for (std::size_t k = 0; k < t.K; ++k) {
260 if (fir[p][k] <= 0 || t.pidx[p][k] < 0)
continue;
261 cvec[
static_cast<std::size_t
>(t.pidx[p][k])] += fir[p][k];
263 for (std::size_t p = 0; p < t.I; ++p)
264 for (std::size_t k = 0; k < t.K; ++k) {
265 const double th = inh[p][k];
268 if (std::isinf(th) || th <= 0 || t.pidx[p][k] < 0)
continue;
269 rec.inh_slot.push_back(
static_cast<std::size_t
>(t.pidx[p][k]));
270 rec.inh_thr.push_back(th);
275 rec.c = std::isnan(c) ? 1.0 : c;
280 const std::function<T(
const std::vector<T>&)> g = tp.
firingdep[m];
281 const std::size_t I = t.I, K = t.K;
282 rec.dep = [g, I, K](
const Matrix<double>& mm) ->
double {
283 std::vector<T> flat(I * K, num_traits<T>::from_int(0));
284 for (std::size_t i = 0; i < I; ++i)
285 for (std::size_t k = 0; k < K; ++k)
286 flat[i * K + k] = num_traits<T>::from_double(mm(i, k));
287 return num_traits<T>::to_double(g(flat));
295 rec.d1.assign(1, 0.0);
296 rec.pie.assign(1, 1.0);
297 rec.closable =
false;
302 throw InputError(
"fluid_petri_terms: mode " + rec.label +
303 " has no Markovian firing process. The renewal families are converted "
304 "to phase type before the solver runs, so this is a distribution the "
305 "fluid Petri route cannot time; use SolverCTMC or SolverLDES");
306 const lang::Distrib<T>& fp = tp.
firingproc[m];
307 Matrix<double> D0, D1;
308 if (fp.D0.rows() > 0 && fp.D1.rows() > 0) {
309 D0 = Matrix<double>(fp.D0.rows(), fp.D0.cols(), 0.0);
310 for (std::size_t i = 0; i < D0.rows(); ++i)
311 for (std::size_t j = 0; j < D0.cols(); ++j)
312 D0(i, j) = num_traits<T>::to_double(fp.D0(i, j));
313 D1 = Matrix<double>(fp.D1.rows(), fp.D1.cols(), 0.0);
314 for (std::size_t i = 0; i < D1.rows(); ++i)
315 for (std::size_t j = 0; j < D1.cols(); ++j)
316 D1(i, j) = num_traits<T>::to_double(fp.D1(i, j));
319 const double mean = num_traits<T>::to_double(fp.mean);
321 throw InputError(
"fluid_petri_terms: mode " + rec.label +
322 " has a non-positive mean firing time");
323 D0 = Matrix<double>(1, 1, -1.0 / mean);
324 D1 = Matrix<double>(1, 1, 1.0 / mean);
329 rec.d1.assign(rec.nph, 0.0);
330 for (std::size_t h = 0; h < rec.nph; ++h) {
332 for (std::size_t hp = 0; hp < D1.cols(); ++hp) acc += D1(h, hp);
335 rec.pie.assign(std::max<std::size_t>(rec.nph, 1), 0.0);
338 for (std::size_t h = 0; h < rec.nph && h < fp.params.size(); ++h) {
339 rec.pie[h] = num_traits<T>::to_double(fp.params[h]);
343 std::fill(rec.pie.begin(), rec.pie.end(), 0.0);
346 for (std::size_t h = 0; h < rec.nph; ++h) rec.pie[h] /= tot;
351 rec.closable = !(rec.arc_slot.size() <= 1 && std::isinf(rec.c));
365 t.
I =
sn.nodes.size();
369 for (std::size_t i = 0; i < t.
I; ++i) t.
names_node[i] =
sn.nodes[i].name;
370 for (std::size_t i = 1; i <= t.
I; ++i) {
377 std::vector<std::size_t> tok;
378 for (std::size_t pi = 0; pi < t.
places.size(); ++pi) {
380 else tok.push_back(t.
places[pi]);
389 t.
m0full.assign(t.
I, std::vector<double>(t.
K, 0.0));
390 for (std::size_t pi = 0; pi < t.
places.size(); ++pi) {
391 const std::size_t ind = t.
places[pi];
392 const typename std::map<std::size_t, std::vector<T>>::const_iterator im =
393 sn.initmarking.find(ind);
394 if (im ==
sn.initmarking.end())
continue;
395 for (std::size_t k = 0; k < t.
K && k < im->second.size(); ++k) {
399 " holds an infinite initial marking of class " +
400 std::to_string(k + 1));
404 bool any_declared =
false;
405 for (std::size_t pi = 0; pi < t.
places.size() && !any_declared; ++pi)
406 any_declared = (
sn.initmarking.find(t.
places[pi]) !=
sn.initmarking.end());
408 for (std::size_t r = 0; r <
sn.classes.size(); ++r) {
410 if (!(njobs > 0.0) || !std::isfinite(njobs))
continue;
411 if (
sn.classes[r].refstat < 1 ||
sn.classes[r].refstat >
sn.station_to_node.size())
413 const std::size_t ref_node =
sn.station_to_node[
sn.classes[r].refstat - 1];
414 if (ref_node >= 1 && ref_node <= t.
I &&
416 t.
m0full[ref_node - 1][r] += njobs;
421 std::vector<std::vector<bool>> touched(t.
I, std::vector<bool>(t.
K,
false));
422 for (std::size_t ti = 0; ti < t.
transitions.size(); ++ti) {
424 const typename std::map<std::size_t, qn::TransitionParam<T>>::const_iterator it =
425 sn.transparam.find(ind);
426 if (it ==
sn.transparam.end())
continue;
428 for (std::size_t m = 0; m < tp.
nmodes; ++m) {
429 const std::vector<std::vector<double>> en =
430 terms_detail::pad(tp.
enabling[m], t.
I, t.
K, 0.0);
431 const std::vector<std::vector<double>> fir =
432 terms_detail::pad(tp.
firing[m], t.
I, t.
K, 0.0);
433 const std::vector<std::vector<double>> inh = terms_detail::pad(
434 tp.
inhibiting[m], t.
I, t.
K, std::numeric_limits<double>::infinity());
435 for (std::size_t i = 0; i < t.
I; ++i)
436 for (std::size_t k = 0; k < t.
K; ++k)
437 if (en[i][k] > 0 || fir[i][k] != 0 ||
438 (!std::isinf(inh[i][k]) && inh[i][k] > 0))
439 touched[i][k] =
true;
445 std::size_t snd, r, qnd, l;
447 std::vector<SrcArr> src_arr;
448 for (std::size_t ind = 1; ind <= t.
I; ++ind) {
450 const std::size_t ist =
sn.nodes[ind - 1].station;
451 if (ist < 1)
continue;
452 for (std::size_t r = 0; r < t.
K; ++r) {
454 if (std::isnan(lambda) || lambda <= 0)
continue;
455 for (std::size_t pi = 0; pi < t.
places.size(); ++pi) {
456 const std::size_t jnd = t.
places[pi];
457 for (std::size_t s = 0; s < t.
K; ++s) {
459 sn.rtnodes((ind - 1) * t.
K + r, (jnd - 1) * t.
K + s));
461 touched[jnd - 1][s] =
true;
467 src_arr.push_back(a);
474 t.
pidx.assign(t.
I, std::vector<std::ptrdiff_t>(t.
K, -1));
476 for (std::size_t pi = 0; pi < t.
places.size(); ++pi) {
477 const std::size_t ind = t.
places[pi];
478 for (std::size_t k = 0; k < t.
K; ++k) {
479 if (!(touched[ind - 1][k] || t.
m0full[ind - 1][k] > 0))
continue;
480 t.
pidx[ind - 1][k] =
static_cast<std::ptrdiff_t
>(nm);
483 t.
coord_station.push_back(
static_cast<std::ptrdiff_t
>(
sn.nodes[ind - 1].station) - 1);
490 std::size_t nstate = nm;
491 for (std::size_t ti = 0; ti < t.
transitions.size(); ++ti) {
493 const typename std::map<std::size_t, qn::TransitionParam<T>>::const_iterator it =
494 sn.transparam.find(ind);
495 if (it ==
sn.transparam.end())
continue;
496 for (std::size_t m = 0; m < it->second.nmodes; ++m) {
497 PetriMode rec = terms_detail::build_mode(
sn, it->second, ind, m, t, nm);
500 for (std::size_t h = 0; h < rec.
nph; ++h) rec.
zblk[h] = nstate + h;
503 t.
modes.push_back(rec);
508 t.
fidx.assign(t.
I, -1);
509 for (std::size_t q = 0; q < t.
nf; ++q) {
512 t.
fidx[ind - 1] =
static_cast<std::ptrdiff_t
>(nstate + q);
516 t.
fluid_station.push_back(
static_cast<std::ptrdiff_t
>(
sn.nodes[ind - 1].station) - 1);
523 for (std::size_t j = 0; j < t.
modes.size(); ++j)
524 if (t.
modes[j].cvec.size() < nstate) t.
modes[j].cvec.resize(nstate, 0.0);
528 const auto level_of = [&](std::size_t node,
const std::string& lbl) -> std::size_t {
529 if (node == 0 || node > t.
I || t.
fidx[node - 1] < 0)
530 throw InputError(
"fluid_petri_terms: mode " + lbl +
" has a fluid arc on a node that is not a "
532 return static_cast<std::size_t
>(t.
fidx[node - 1]);
534 for (std::size_t j = 0; j < t.
modes.size(); ++j) {
537 const std::vector<typename qn::TransitionParam<T>::FluidArc>& imp = tp.
fluid_impulses(md.
mode);
538 for (std::size_t a = 0; a < imp.size(); ++a) md.
cvec[level_of(imp[a].node, md.
label)] += imp[a].value;
539 const std::vector<typename qn::TransitionParam<T>::FluidArc>& fr = tp.
fluid_rates(md.
mode);
540 const std::vector<typename qn::TransitionParam<T>::FluidFlowDep>& fld = tp.
fluid_flow_deps(md.
mode);
541 const std::size_t KK = t.
K;
542 for (std::size_t a = 0; a < fr.size(); ++a) {
547 for (std::size_t u = 0; u < fld.size(); ++u) {
548 if (fld[u].node != fr[a].node)
continue;
550 const std::function<double(
const std::vector<double>&)> phi = fld[u].fun;
552 std::vector<double> flat(mm.rows() * KK, 0.0);
553 for (std::size_t i = 0; i < mm.rows(); ++i)
554 for (std::size_t k = 0; k < KK && k < mm.cols(); ++k) flat[i * KK + k] = mm(i, k);
560 const std::vector<typename qn::TransitionParam<T>::FluidGuard>& gd = tp.
fluid_guards(md.
mode);
561 for (std::size_t a = 0; a < gd.size(); ++a) {
566 const std::vector<typename qn::TransitionParam<T>::FluidDep>& fd = tp.
fluid_deps(md.
mode);
567 for (std::size_t a = 0; a < fd.size(); ++a) {
572 for (std::size_t j = 0; j < t.
modes.size(); ++j) {
578 std::vector<std::vector<double>> cols;
579 std::vector<double> rate_base;
580 std::vector<int> ev_kind, ev_mode, ev_phase, ev_to;
581 std::vector<std::ptrdiff_t> ev_station, ev_class;
582 std::vector<std::size_t> ev_flow;
583 const auto emit = [&](
const std::vector<double>& col,
double base,
int kind,
int mode,
584 int phase,
int to, std::ptrdiff_t station, std::ptrdiff_t cls) {
586 rate_base.push_back(base);
587 ev_kind.push_back(kind);
588 ev_mode.push_back(mode);
589 ev_phase.push_back(phase);
591 ev_station.push_back(station);
592 ev_class.push_back(cls);
595 for (std::size_t q = 0; q < t.
timed_idx.size(); ++q) {
599 emit(md.
cvec, md.
d1[0], 1,
static_cast<int>(j), 0, 0, -1, -1);
601 for (std::size_t h = 0; h < md.
nph; ++h)
602 for (std::size_t hp = 0; hp < md.
nph; ++hp) {
603 const double w = md.
D1(h, hp);
604 if (w <= 0)
continue;
605 std::vector<double> col = md.
cvec;
606 col[md.
zblk[hp]] += 1.0;
607 col[md.
zblk[h]] -= 1.0;
608 emit(col, w, 1,
static_cast<int>(j),
static_cast<int>(h),
609 static_cast<int>(hp), -1, -1);
611 for (std::size_t h = 0; h < md.
nph; ++h)
612 for (std::size_t hp = 0; hp < md.
nph; ++hp) {
613 if (hp == h)
continue;
614 const double w = md.
D0(h, hp);
615 if (w <= 0)
continue;
616 std::vector<double> col(nstate, 0.0);
617 col[md.
zblk[hp]] = 1.0;
618 col[md.
zblk[h]] = -1.0;
619 emit(col, w, 2,
static_cast<int>(j),
static_cast<int>(h),
620 static_cast<int>(hp), -1, -1);
628 for (std::size_t q = 0; q < t.
timed_idx.size(); ++q) {
631 if (md.
nph <= 1)
continue;
632 std::vector<double> col(nstate, 0.0);
633 for (std::size_t h = 0; h < md.
nph; ++h) col[md.
zblk[h]] = md.
pie[h];
634 emit(col, 1.0, 5,
static_cast<int>(j), 0, 0, -1, -1);
636 for (std::size_t q = 0; q < t.
imm_idx.size(); ++q) {
637 const std::size_t j = t.
imm_idx[q];
638 emit(t.
modes[j].cvec, 1.0, 4,
static_cast<int>(j), 0, 0, -1, -1);
640 for (std::size_t a = 0; a < src_arr.size(); ++a) {
641 const SrcArr& rec = src_arr[a];
642 const std::size_t ist =
sn.nodes[rec.snd - 1].station;
643 if (ist >= 1 && ist <=
sn.stations.size()) {
647 "fluid_petri_terms: source " + t.
names_node[rec.snd - 1] +
648 " has a non-exponential arrival for class " + std::to_string(rec.r + 1) +
649 ". The fluid Petri route models an arrival as a constant-propensity event, "
650 "which a renewal stream with memory is not; use SolverCTMC, SolverJMT or "
653 std::vector<double> col(nstate, 0.0);
654 col[
static_cast<std::size_t
>(t.
pidx[rec.qnd - 1][rec.l])] = 1.0;
658 sn.rtnodes((rec.snd - 1) * t.
K + rec.r, (rec.qnd - 1) * t.
K + rec.l));
659 emit(col, base, 3, -1, 0, 0,
static_cast<std::ptrdiff_t
>(ist) - 1,
660 static_cast<std::ptrdiff_t
>(rec.r));
664 for (std::size_t q = 0; q < t.
timed_idx.size(); ++q) {
667 for (std::size_t a = 0; a < md.
flow_slot.size(); ++a) {
668 std::vector<double> col(nstate, 0.0);
670 emit(col, std::fabs(md.
flow_rate[a]), 6,
static_cast<int>(j), 0, 0, -1, -1);
671 ev_flow.resize(rate_base.size(), 0);
678 for (std::size_t e = 0; e < t.
nev; ++e)
679 for (std::size_t s = 0; s < nstate; ++s)
680 if (cols[e][s] != 0.0) t.
D(s, e) = cols[e][s];
688 ev_flow.resize(t.
nev, 0);
692 std::map<std::pair<std::size_t, std::size_t>, std::size_t> pairkey;
693 for (std::size_t j = 0; j < t.
modes.size(); ++j) {
696 for (std::size_t a = 0; a < md.
arc_slot.size(); ++a)
697 for (std::size_t b = a; b < md.
arc_slot.size(); ++b)
700 for (std::size_t b = 0; b < md.
inh_slot.size(); ++b)
704 for (std::size_t b = 0; b < md.
guard_slot.size(); ++b)
709 const std::size_t pn = std::max<std::size_t>(nstate, 1);
710 t.
pair_index.assign(pn, std::vector<std::ptrdiff_t>(pn, -1));
711 for (std::size_t i = 0; i < t.
npair; ++i) {
713 static_cast<std::ptrdiff_t
>(i);
715 static_cast<std::ptrdiff_t
>(i);
718 for (std::size_t e = 0; e < t.
nev; ++e) {
727 for (std::size_t q = 0; q < t.
timed_idx.size(); ++q)
730 for (std::size_t s = 0; s < nstate; ++s) t.
cov_idx[s] = s;
738 for (std::size_t e = 0; e < t.
nev; ++e) {
741 const std::size_t kk =
743 static_cast<std::size_t
>(t.
ev_class[e]);
749 for (std::size_t a = 0; a < md.
arc_slot.size(); ++a) {
750 const std::size_t s = md.
arc_slot[a];
752 const std::size_t kk =
760 t.
x0.assign(nstate, 0.0);
763 for (std::size_t j = 0; j < t.
modes.size(); ++j) {
765 if (md.
nph <= 1)
continue;
766 double e = std::numeric_limits<double>::infinity();
767 for (std::size_t a = 0; a < md.
arc_slot.size(); ++a)
770 for (std::size_t h = 0; h < md.
nph; ++h) t.
x0[md.
zblk[h]] = std::min(e, md.
c) * md.
pie[h];
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
The exception types the port throws.
Dense matrix and non-owning view.
double petri_coarse_tol()
GlobalConstants.CoarseTol, also the relative width of the seed's smoothed inhibitor gate.
PetriTerms petri_build_terms(const qn::NetworkStruct< T > &sn)
Assemble the drift terms of a net.
double petri_fine_tol()
GlobalConstants.FineTol, the reference's own "effectively zero".
TimingStrategy
SPN transition timing, with the values of MATLAB TimingStrategy.
@ IMMEDIATE
fires with zero delay, resolved by weight and priority
@ TIMED
fires after its firing distribution elapses
ProcessType
Distribution kinds, with the values of MATLAB ProcessType.
double tot(const std::vector< double > &pops)
Conservation laws of a layered queueing network, enumerated from its structure.
A queueing network and its refreshed NetworkStruct.
The <kind> part of a LINE:<category>:<kind> identifier (see _kb/17-error-vocabulary....
One firing mode of one transition, with its arcs and its firing process.
std::vector< std::function< double(double)> > fdep_fun
std::vector< double > flow_rate
double c
servers of this mode; infinite for none
std::vector< double > guard_thr
std::size_t mode
mode index within it, 0-based
std::vector< double > d1
row sums of D1, the completion rate out of each phase
std::vector< int > guard_sgn
std::vector< std::size_t > inh_slot
Inhibitor arcs, as state coordinates and their thresholds.
lang::TimingStrategy timing
std::vector< std::size_t > arc_slot
Input arcs, as state coordinates and their multiplicities.
std::vector< std::size_t > flow_slot
Fluid flows of the mode: level coordinates and signed rates per running server.
std::vector< double > pie
entry distribution over the phases
std::vector< std::vector< std::size_t > > flow_dep_read
std::size_t nph
phases of the firing process; 0 for an immediate mode
std::vector< std::size_t > zblk
The phase coordinates of a multi-phase mode; empty otherwise.
std::vector< std::size_t > guard_slot
Fluid guards: level coordinates, +1 for '>=' and -1 for '<=', and thresholds.
std::vector< double > arc_w
std::vector< std::function< double(const Matrix< double > &)> > flow_dep_fun
Marking-dependent flow multipliers, aligned with flow_slot (an empty function is the unit one),...
std::vector< double > inh_thr
std::function< double(const Matrix< double > &)> dep
Marking-dependent firing multiplier; empty for the unit one.
std::size_t node
1-based node index of the transition
std::vector< std::size_t > fdep_slot
Fluid rate dependences: level coordinates and the multipliers h(level).
std::vector< double > cvec
The mode's incidence column, over the whole state.
bool closable
Whether the enabling degree is worth closing over.
The assembled drift terms of a net.
std::vector< std::size_t > flow_col
std::vector< std::vector< double > > m0full
std::vector< std::size_t > stoch_col
std::vector< double > rate_base
std::vector< std::size_t > coord_class
std::vector< std::size_t > places
std::size_t nstate
marking coordinates plus phase coordinates plus fluid levels
std::vector< std::size_t > imm_col
std::vector< std::vector< std::ptrdiff_t > > pidx
pidx(p,k) is the state coordinate of (0-based node p, class k), or npos.
std::vector< std::size_t > transitions
1-based node indices
std::vector< std::size_t > latch_col
std::vector< std::vector< std::ptrdiff_t > > pair_index
std::vector< std::size_t > imm_idx
std::vector< std::size_t > timed_idx
std::size_t nm
marking coordinates alone
std::vector< std::ptrdiff_t > fluid_station
0-based station of each fluid place
std::vector< std::string > names_node
0-based, one per node
std::vector< int > ev_phase
std::vector< double > fluid_init
std::vector< std::size_t > coord_node
std::vector< int > ev_kind
std::vector< std::pair< std::size_t, std::size_t > > cov_pairs
The Sigma entries the closure reads, and the map back to them.
std::vector< std::string > fluid_name
std::map< std::size_t, std::vector< std::size_t > > producers
std::vector< std::size_t > ev_flow
Kind 6: the flow's position in its mode's flow_slot; 0 for every other kind.
std::map< std::size_t, std::vector< std::size_t > > consumers
(station*K + class) -> the events that take tokens out of / into it.
std::vector< std::ptrdiff_t > ev_class
std::vector< std::size_t > cov_idx
std::map< std::size_t, std::vector< double > > consumer_w
std::vector< std::size_t > latch_mode
std::vector< double > fluid_cap
std::vector< int > ev_mode
std::vector< std::ptrdiff_t > ev_station
std::vector< std::size_t > fluid_slot
std::vector< PetriMode > modes
std::vector< std::ptrdiff_t > fidx
(I) level coordinate of a 0-based node, or -1
std::vector< std::size_t > fluid_places
Fluid places (FSPN): 1-based nodes, their level coordinates, capacities and initial levels.
std::vector< std::ptrdiff_t > coord_station
Matrix< double > D
(nstate x nev) incidence
One station of the network.
The parameters of a Transition node: MATLAB sn.nodeparam{ind} for an SPN transition,...
const std::vector< FluidArc > & fluid_rates(std::size_t m) const
std::vector< double > firingprio
firing priority per mode
std::vector< lang::TimingStrategy > timing
immediate or timed
std::vector< std::string > modenames
std::vector< lang::Distrib< T > > firingproc
firing distribution per mode
std::vector< double > nmodeservers
servers per mode, may be infinite
const std::vector< FluidArc > & fluid_impulses(std::size_t m) const
std::vector< T > fireweight
weight among simultaneously enabled modes
std::vector< Matrix< T > > firing
firing[m](p,r): class-r tokens mode m moves to/from place p when it fires.
std::vector< Matrix< T > > enabling
enabling[m](p,r): class-r tokens of place p (0-based node) mode m needs.
const std::vector< FluidDep > & fluid_deps(std::size_t m) const
const std::vector< FluidFlowDep > & fluid_flow_deps(std::size_t m) const
std::vector< std::function< T(const std::vector< T > &)> > firingdep
Marking-dependent firing-rate multiplier g_m(marking); an empty entry is the unit multiplier.
std::vector< Matrix< T > > inhibiting
inhibiting[m](p,r): class-r tokens of p that BLOCK mode m (Inf = never).
const std::vector< FluidGuard > & fluid_guards(std::size_t m) const