5#ifndef LINE_SOLVERS_FLUID_PETRI_SYSTEM_H
6#define LINE_SOLVERS_FLUID_PETRI_SYSTEM_H
36inline double norm_cdf(
double z) {
return 0.5 * std::erfc(-z / std::sqrt(2.0)); }
40 return std::exp(-0.5 * z * z) / std::sqrt(2.0 * 3.14159265358979323846);
48inline std::pair<double, double>
min_closure(
double n,
double c,
double s2,
double vc,
50 if (std::isinf(c))
return std::make_pair(n, 1.0);
51 const double th2 = s2 - 2.0 * cov + vc;
57 return std::make_pair(n, 1.0);
58 return std::make_pair(c, 0.0);
60 const double th = std::sqrt(th2);
61 const double al = (n - c) / th;
64 const double h = n * p + c * (1.0 - p) - th * phi;
65 return std::make_pair(h, p);
71 std::vector<double>
g;
88 const std::size_t A = mu.size();
93 out.
h = std::min(1.0, c);
97 std::vector<std::vector<double>> s(A, std::vector<double>(A, 0.0));
99 for (std::size_t i = 0; i < A; ++i)
100 for (std::size_t j = 0; j < A; ++j) s[i][j] = S(i, j);
104 std::vector<double> covz(A, 0.0);
105 for (std::size_t i = 0; i < A; ++i) covz[i] = s[0][i];
106 std::vector<double> p(A, 1.0);
108 for (std::size_t k = 1; k < A; ++k) {
109 double th2 = vz + s[k][k] - 2.0 * covz[k];
111 if (th2 < 0.0) th2 = 0.0;
112 const double th = std::sqrt(th2);
114 std::vector<double> cw(A, 0.0);
116 const double al = (mz - mu[k]) / th;
120 mw = mz * pk + mu[k] * Phi - th * phi;
121 const double e2 = (mz * mz + vz) * pk + (mu[k] * mu[k] + s[k][k]) * Phi -
122 (mz + mu[k]) * th * phi;
127 if (vw < 0.0) vw = 0.0;
128 for (std::size_t i = 0; i < A; ++i) cw[i] = covz[i] * pk + s[i][k] * Phi;
130 pk = (mu[k] - mz >
petri_fine_tol() * std::max(1.0, std::fabs(mz))) ? 1.0 : 0.0;
131 mw = std::min(mz, mu[k]);
132 vw = pk * vz + (1.0 - pk) * s[k][k];
133 for (std::size_t i = 0; i < A; ++i) cw[i] = covz[i] * pk + s[i][k] * (1.0 - pk);
144 const std::pair<double, double> capped =
min_closure(mz, c, vz, 0.0, 0.0);
145 out.
h = capped.first;
146 out.
g.assign(A, 0.0);
147 double tail = capped.second;
148 for (std::size_t a = A - 1; a >= 1; --a) {
149 out.
g[a] = (1.0 - p[a]) * tail;
159 std::vector<std::vector<std::size_t>>
dslot;
160 std::vector<std::vector<double>>
dval;
162 std::vector<std::vector<std::size_t>>
depslot;
166namespace system_detail {
169inline double sig(
const PetriTerms& t,
const std::vector<double>& s2, std::size_t a,
173 return (i < 0 ||
static_cast<std::size_t
>(i) >= s2.size()) ? 0.0
174 : s2[
static_cast<std::size_t
>(i)];
186inline void dep_of(
const PetriTerms& t,
const PetriMode& md,
const std::vector<double>& x,
187 PetriTheta& th, std::size_t j) {
189 for (std::size_t s = 0; s < t.nm; ++s) mm(t.coord_node[s], t.coord_class[s]) = x[s];
190 th.dep[j] = md.dep(mm);
191 for (std::size_t s = 0; s < t.nm; ++s) {
192 const double h = std::max(1e-6 * std::fabs(x[s]), 1e-6);
193 const std::size_t i = t.coord_node[s], k = t.coord_class[s];
195 mp(i, k) = mm(i, k) + h;
196 mn(i, k) = std::max(0.0, mm(i, k) - h);
197 const double hh = mp(i, k) - mn(i, k);
198 if (hh <= 0)
continue;
199 const double d = (md.dep(mp) - md.dep(mn)) / hh;
201 th.depslot[j].push_back(s);
202 th.depval[j].push_back(d);
227 const std::vector<double>& s2_in) {
228 const std::size_t nmod = t.
modes.size();
230 th.
theta.assign(nmod, 0.0);
231 th.
dslot.assign(nmod, std::vector<std::size_t>());
232 th.
dval.assign(nmod, std::vector<double>());
233 th.
dep.assign(nmod, 1.0);
234 th.
depslot.assign(nmod, std::vector<std::size_t>());
235 th.
depval.assign(nmod, std::vector<double>());
236 const std::vector<double> zeros(std::max<std::size_t>(t.
npair, 1), 0.0);
237 const std::vector<double>& s2 = s2_in.empty() ? zeros : s2_in;
239 for (std::size_t j = 0; j < nmod; ++j) {
241 const std::size_t A = md.
arc_slot.size();
242 std::vector<double> mu(A, 0.0);
243 for (std::size_t a = 0; a < A; ++a) mu[a] = x[md.
arc_slot[a]] / md.
arc_w[a];
247 for (std::size_t a = 0; a < A; ++a)
248 for (std::size_t b = 0; b < A; ++b)
254 const std::size_t nb = md.
inh_slot.size();
255 std::vector<double> gate(nb, 0.0), dgate(nb, 0.0);
257 for (std::size_t b = 0; b < nb; ++b) {
258 const double mb = x[md.
inh_slot[b]];
259 const double thr = md.
inh_thr[b];
260 const double vb = system_detail::sig(t, s2, md.
inh_slot[b], md.
inh_slot[b]);
262 const double sd = std::sqrt(vb);
263 const double zb = (thr - mb) / sd;
267 gate[b] = (mb < thr -
petri_fine_tol() * std::max(1.0, thr)) ? 1.0 : 0.0;
274 std::map<std::size_t, double> acc;
275 for (std::size_t a = 0; a < A; ++a)
277 for (std::size_t b = 0; b < nb; ++b) {
280 others = ginh / gate[b];
283 for (std::size_t q = 0; q < nb; ++q)
284 if (q != b) others *= gate[q];
286 acc[md.
inh_slot[b]] += mm.
h * others * dgate[b];
288 for (std::map<std::size_t, double>::const_iterator it = acc.begin(); it != acc.end();
290 th.
dslot[j].push_back(it->first);
291 th.
dval[j].push_back(it->second);
293 th.
theta[j] = ginh * mm.
h;
295 if (md.
dep) system_detail::dep_of(t, md, x, th, j);
311 const std::vector<double>& phi,
312 const std::vector<double>& mu,
const PetriTheta& th) {
313 const std::size_t nmod = t.
modes.size();
314 std::vector<std::ptrdiff_t> imm_pos(nmod, -1), latch_pos(nmod, -1);
315 for (std::size_t q = 0; q < t.
imm_idx.size(); ++q)
316 imm_pos[t.
imm_idx[q]] =
static_cast<std::ptrdiff_t
>(q);
317 for (std::size_t q = 0; q < t.
latch_mode.size(); ++q)
318 latch_pos[t.
latch_mode[q]] =
static_cast<std::ptrdiff_t
>(q);
320 std::vector<double> r(t.
nev, 0.0);
321 for (std::size_t e = 0; e < t.
nev; ++e) {
326 const std::ptrdiff_t at = imm_pos[
static_cast<std::size_t
>(t.
ev_mode[e])];
327 r[e] = (phi.empty() || at < 0) ? 0.0 : phi[
static_cast<std::size_t
>(at)];
329 const std::ptrdiff_t at = latch_pos[
static_cast<std::size_t
>(t.
ev_mode[e])];
330 r[e] = (mu.empty() || at < 0) ? 0.0 : mu[
static_cast<std::size_t
>(at)];
332 const std::size_t j =
static_cast<std::size_t
>(t.
ev_mode[e]);
353 for (std::size_t e = 0; e < t.
nev; ++e) {
355 if (k == 3 || k == 4 || k == 5)
continue;
356 const std::size_t j =
static_cast<std::size_t
>(t.
ev_mode[e]);
360 for (std::size_t q = 0; q < th.
dslot[j].size(); ++q)
361 Jr(e, th.
dslot[j][q]) += base * th.
dep[j] * th.
dval[j][q];
362 for (std::size_t q = 0; q < th.
depslot[j].size(); ++q)
365 const std::size_t zc = md.
zblk[
static_cast<std::size_t
>(t.
ev_phase[e])];
The exception types the port throws.
Event-based representation of the fluid marking process of a stochastic Petri net.
Dense linear algebra over the templated number type: products, identity, inverse, and powers.
Dense matrix and non-owning view.
MinMulti minmulti_closure(const std::vector< double > &mu, const Matrix< double > &S, double c)
Min-normal closure of E[min(X_1,...,X_A,c)] by Clark's (1961) recursion.
double norm_cdf(double z)
The standard normal CDF, without a statistics dependency.
std::pair< double, double > min_closure(double n, double c, double s2, double vc, double cov)
E[min(X,Y)] and dE/dE[X] for jointly normal X, Y.
std::vector< double > petri_rates(const PetriTerms &t, const std::vector< double > &x, const std::vector< double > &phi, const std::vector< double > &mu, const PetriTheta &th)
The rate of every event column.
Matrix< double > petri_jacobian(const PetriTerms &t, const PetriTheta &th)
Drift Jacobian A = D * dR/dX.
double petri_fine_tol()
GlobalConstants.FineTol, the reference's own "effectively zero".
double norm_pdf(double z)
The standard normal density.
PetriTheta petri_theta(const PetriTerms &t, const std::vector< double > &x, const std::vector< double > &s2_in)
The closed enabling term of every mode, and its derivative.
Matrix< T > matmul(const Matrix< T > &A, const Matrix< T > &B)
Matrix product A B.
The result of the many-argument closure.
std::vector< double > g
dH/dMU(a): the probability that arc a binds
double v
Var[min] before the cap.
double h
E[min(X_1,...,X_A,c)].
One firing mode of one transition, with its arcs and its firing process.
double c
servers of this mode; infinite for none
std::vector< std::size_t > inh_slot
Inhibitor arcs, as state coordinates and their thresholds.
std::vector< std::size_t > arc_slot
Input arcs, as state coordinates and their multiplicities.
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< double > arc_w
std::vector< double > inh_thr
std::function< double(const Matrix< double > &)> dep
Marking-dependent firing multiplier; empty for the unit one.
bool closable
Whether the enabling degree is worth closing over.
The assembled drift terms of a net.
std::vector< double > rate_base
std::size_t nstate
marking coordinates plus phase coordinates
std::vector< std::vector< std::ptrdiff_t > > pair_index
std::vector< std::size_t > imm_idx
std::vector< int > ev_phase
std::vector< int > ev_kind
std::vector< std::size_t > latch_mode
std::vector< int > ev_mode
std::vector< PetriMode > modes
Matrix< double > D
(nstate x nev) incidence
The closed enabling term of every mode and its derivative.
std::vector< std::vector< double > > dval
std::vector< std::vector< double > > depval
std::vector< double > theta
std::vector< std::vector< std::size_t > > dslot
std::vector< double > dep
std::vector< std::vector< std::size_t > > depslot