LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
ldes_spn.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_LDES_LDES_SPN_H
6#define LINE_SOLVERS_LDES_LDES_SPN_H
7
8/**
9 * @file
10 * @ingroup line_solvers
11 * The Petri-net layer of the native LDES engine: Places and Transitions.
12 *
13 * A PLACE holds tokens per class and a TRANSITION moves them. A mode of a
14 * transition is ENABLED when every input place holds at least its enabling
15 * count and no inhibiting count is met; firing consumes the enabling tokens and
16 * deposits the firing counts.
17 *
18 * IMMEDIATE MODES FIRE BEFORE ANY TIMED ONE, and among themselves in priority
19 * order, weighted at equal priority. That is not an optimization: an immediate
20 * transition takes zero time, so a marking that enables one is not a marking
21 * the net ever rests in, and letting a timed mode fire from it would visit a
22 * state the model does not have.
23 *
24 * THE FIRING RATE MAY DEPEND ON THE MARKING. `firingdep` multiplies the mode's
25 * nominal rate by g(marking), and the clock has to be RESAMPLED whenever the
26 * marking changes, not merely scaled: an exponential clock drawn under one
27 * rate and left to run carries the old rate into the new marking.
28 */
29
30#include <algorithm>
31#include <cmath>
32#include <cstddef>
33#include <functional>
34#include <limits>
35#include <tuple>
36#include <vector>
37
39
40namespace line {
41namespace ldes {
42namespace engine {
43
44/**
45 * One mode of a transition, resolved to what the event loop needs.
46 *
47 * THE ARC VECTORS ARE INDEXED BY (place slot, class), flattened `p * K + r`,
48 * and the marking handed to `spn_enabled` and `spn_fire` uses the same layout.
49 * A Petri net whose arcs carry a class is a COLOURED net and its behaviour is
50 * not that of the class-summed one: a mode needing two Class1 tokens must not
51 * be enabled by two Class2 tokens sitting at the same place.
52 */
53struct SpnMode {
54 std::vector<double> enabling; ///< per (place, class), tokens required
55 std::vector<double> inhibiting; ///< per (place, class), tokens that block (inf = never)
56 std::vector<double> firing; ///< per (place, class), tokens moved on a firing
57 double servers = 1.0;
58 double priority = 0.0;
59 double weight = 1.0;
60 bool immediate = false;
61 double rate = 1.0; ///< nominal firing rate of a timed mode
62 std::function<double(const std::vector<double>&)> dep; ///< marking multiplier
63 /**
64 * Output arcs to NODES THAT ARE NOT PLACES, (node, class, count): a Sink takes the
65 * token out of the net, a Queue or a Fork receives it as a job, as `routeTokenFromTransition`.
66 */
67 std::vector<std::tuple<std::size_t, std::size_t, double>> exits;
68};
69
70/** One Transition node. */
72 std::size_t node = 0;
73 std::vector<SpnMode> modes;
74 std::vector<std::size_t> places; ///< the place NODES its modes reference, in order
75 std::vector<double> fired; ///< per mode
76};
77
78/**
79 * True when `m` is enabled by the marking `tok`, which is indexed the same way
80 * as the mode's own vectors -- (place slot, class), flattened.
81 *
82 * An INHIBITING arc is a bound, not a requirement: the mode is blocked once the
83 * place reaches the count IN THAT CLASS, and an infinite count never blocks.
84 */
85inline bool spn_enabled(const SpnMode& m, const std::vector<double>& tok) {
86 for (std::size_t p = 0; p < m.enabling.size() && p < tok.size(); ++p)
87 if (tok[p] < m.enabling[p]) return false;
88 for (std::size_t p = 0; p < m.inhibiting.size() && p < tok.size(); ++p)
89 if (std::isfinite(m.inhibiting[p]) && m.inhibiting[p] > 0.0 && tok[p] >= m.inhibiting[p])
90 return false;
91 return true;
92}
93
94/** The rate of a timed mode under the current marking. */
95inline double spn_rate(const SpnMode& m, const std::vector<double>& tok) {
96 double r = m.rate;
97 if (m.dep) {
98 const double g = m.dep(tok);
99 r *= (g > 0.0) ? g : 0.0;
100 }
101 return r;
102}
103
104/**
105 * The clocks an enabled timed mode runs at once: min(servers, enabling degree), the degree being
106 * the floor over its input arcs of tokens over weight on the FULL marking, as the CTMC's
107 * State.afterGlobalEvent counts them. A mode with no input arc runs one clock.
108 */
109inline double spn_active_servers(const SpnMode& m, const std::vector<double>& tok) {
110 double degree = std::numeric_limits<double>::infinity();
111 for (std::size_t p = 0; p < m.enabling.size() && p < tok.size(); ++p)
112 if (m.enabling[p] > 0.0) degree = std::min(degree, std::floor(tok[p] / m.enabling[p]));
113 if (!std::isfinite(degree)) return 1.0;
114 return std::min(m.servers, degree);
115}
116
117/** Move the tokens of one firing: consume the enabling counts, deposit the firing ones. */
118inline void spn_fire(const SpnMode& m, std::vector<double>& tok) {
119 for (std::size_t p = 0; p < m.enabling.size() && p < tok.size(); ++p)
120 tok[p] -= m.enabling[p];
121 for (std::size_t p = 0; p < m.firing.size() && p < tok.size(); ++p) tok[p] += m.firing[p];
122}
123
124/**
125 * Pick among the enabled IMMEDIATE modes: the highest priority first (lowest
126 * value), then weighted at random among the ties. Returns -1 when none is
127 * enabled.
128 */
129inline int spn_pick_immediate(const std::vector<SpnMode>& modes, const std::vector<double>& tok,
130 double u) {
131 double best_prio = std::numeric_limits<double>::infinity();
132 for (const SpnMode& m : modes)
133 if (m.immediate && spn_enabled(m, tok)) best_prio = std::min(best_prio, m.priority);
134 if (!std::isfinite(best_prio)) return -1;
135 double total = 0.0;
136 for (const SpnMode& m : modes)
137 if (m.immediate && m.priority == best_prio && spn_enabled(m, tok)) total += m.weight;
138 if (!(total > 0.0)) {
139 for (std::size_t k = 0; k < modes.size(); ++k)
140 if (modes[k].immediate && modes[k].priority == best_prio && spn_enabled(modes[k], tok))
141 return static_cast<int>(k);
142 return -1;
143 }
144 double acc = 0.0;
145 const double x = u * total;
146 for (std::size_t k = 0; k < modes.size(); ++k)
147 if (modes[k].immediate && modes[k].priority == best_prio && spn_enabled(modes[k], tok)) {
148 acc += modes[k].weight;
149 if (x < acc) return static_cast<int>(k);
150 }
151 return -1;
152}
153
154} // namespace engine
155} // namespace ldes
156} // namespace line
157
158#endif // LINE_SOLVERS_LDES_LDES_SPN_H
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
double spn_rate(const SpnMode &m, const std::vector< double > &tok)
The rate of a timed mode under the current marking.
Definition ldes_spn.h:95
double spn_active_servers(const SpnMode &m, const std::vector< double > &tok)
The clocks an enabled timed mode runs at once: min(servers, enabling degree), the degree being the fl...
Definition ldes_spn.h:109
int spn_pick_immediate(const std::vector< SpnMode > &modes, const std::vector< double > &tok, double u)
Pick among the enabled IMMEDIATE modes: the highest priority first (lowest value),...
Definition ldes_spn.h:129
bool spn_enabled(const SpnMode &m, const std::vector< double > &tok)
True when m is enabled by the marking tok, which is indexed the same way as the mode's own vectors – ...
Definition ldes_spn.h:85
void spn_fire(const SpnMode &m, std::vector< double > &tok)
Move the tokens of one firing: consume the enabling counts, deposit the firing ones.
Definition ldes_spn.h:118
Conservation laws of a layered queueing network, enumerated from its structure.
Definition aoi_dist2ph.h:52
One mode of a transition, resolved to what the event loop needs.
Definition ldes_spn.h:53
std::vector< double > enabling
per (place, class), tokens required
Definition ldes_spn.h:54
std::function< double(const std::vector< double > &)> dep
marking multiplier
Definition ldes_spn.h:62
std::vector< std::tuple< std::size_t, std::size_t, double > > exits
Output arcs to NODES THAT ARE NOT PLACES, (node, class, count): a Sink takes the token out of the net...
Definition ldes_spn.h:67
double rate
nominal firing rate of a timed mode
Definition ldes_spn.h:61
std::vector< double > inhibiting
per (place, class), tokens that block (inf = never)
Definition ldes_spn.h:55
std::vector< double > firing
per (place, class), tokens moved on a firing
Definition ldes_spn.h:56
One Transition node.
Definition ldes_spn.h:71
std::vector< double > fired
per mode
Definition ldes_spn.h:75
std::vector< std::size_t > places
the place NODES its modes reference, in order
Definition ldes_spn.h:74
std::vector< SpnMode > modes
Definition ldes_spn.h:73