LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
spn_conv.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_API_SPN_SPN_CONV_H
6
#define LINE_API_SPN_SPN_CONV_H
7
8
/**
9
* @file
10
* @ingroup api_spn
11
* Convolution algorithm for the normalising constant of an S-invariant
12
* reachable product-form stochastic Petri net.
13
*
14
* J. Coleman, W. Henderson, P. Taylor, "Product form equilibrium distributions
15
* and a convolution algorithm for stochastic Petri nets", Performance
16
* Evaluation 26(3), 1996, 159-180; presented as the point of comparison for
17
* MDD-rec in S. Balsamo, A. Marin, I. Stojic, FGCS 111 (2020), Sec. 5.1.
18
*
19
* With S the minimal-support S-invariant matrix and V = S m0 the load vector,
20
* the reachability set of an S-INVARIANT REACHABLE net is exactly
21
* {m >= 0 : S m = V}, and conditioning on the marking of one place partitions it
22
* (Lemma 5.1). Writing G_j(W) for the mass of the markings supported on the
23
* first j places with S m = W,
24
*
25
* G_0(W) = [W == 0], G_j(W) = sum_i g_j(i) G_{j-1}(W - i S_j),
26
*
27
* and G = G_n(V). On a net whose only invariant is "the tokens are conserved"
28
* this is Buzen's convolution for a closed queueing network, one place per
29
* station.
30
*
31
* NO ILP IS SOLVED. The paper obtains the marking set M_p(P',W) from the
32
* feasibility of an integer program (Prop. 5.2) so that the sum skips the terms
33
* that contribute nothing. Here the sum simply runs over i whose residual
34
* W - i S_j stays non-negative and the recursion returns zero on an infeasible
35
* residual, which gives the same value: the ILP is an optimisation of the
36
* enumeration, not part of the definition. Memoising on (j, W) keeps the walk
37
* over the reachable residuals rather than over all of them.
38
*
39
* S-INVARIANT REACHABILITY IS NOT CHECKED, and cannot be cheaply: no algorithm
40
* is known that decides it without generating the reachability set (FGCS, Sec.
41
* 5.1). On a net that fails it, {m : S m = V} is strictly larger than the
42
* reachable set and this returns a normalising constant over unreachable
43
* markings too, which is why `mdd::mdd_rec` -- which walks the reachable set
44
* itself -- is the general algorithm and this one the special case. Compare the
45
* two on a new net before trusting this one on it.
46
*/
47
48
#include <cstddef>
49
#include <map>
50
#include <vector>
51
52
#include "
line/api/spn/spn_sinvariants.h
"
53
#include "
line/num/number.h
"
54
#include "
line/util/error.h
"
55
56
namespace
line
{
57
namespace
spn
{
58
59
namespace
detail {
60
61
template
<
class
T>
62
T spn_conv_rec(std::size_t j,
const
std::vector<long long>& W,
63
const
std::vector<std::vector<long long>>& S,
64
const
std::vector<std::vector<T>>& g,
65
std::map<std::pair<std::size_t, std::vector<long long>>, T>& memo) {
66
const
T zero =
num_traits<T>::from_int
(0), one =
num_traits<T>::from_int
(1);
67
if
(j == 0) {
68
for
(std::size_t r = 0; r < W.size(); ++r)
69
if
(W[r] != 0)
return
zero;
70
return
one;
71
}
72
const
std::pair<std::size_t, std::vector<long long>> key(j, W);
73
const
typename
std::map<std::pair<std::size_t, std::vector<long long>>, T>::const_iterator it =
74
memo.find(key);
75
if
(it != memo.end())
return
it->second;
76
77
const
std::size_t p = j - 1;
78
T acc = zero;
79
for
(std::size_t i = 0; i < g[p].size(); ++i) {
80
std::vector<long long> rem = W;
81
bool
feasible =
true
;
82
for
(std::size_t r = 0; r < W.size() && feasible; ++r) {
83
rem[r] -=
static_cast<
long
long
>
(i) * S[r][p];
84
if
(rem[r] < 0) feasible =
false
;
85
}
86
if
(!feasible)
break
;
// S is non-negative, so larger i only gets worse
87
if
(g[p][i] == zero)
continue
;
88
acc += T(g[p][i] * spn_conv_rec(j - 1, rem, S, g, memo));
89
}
90
memo[key] = acc;
91
return
acc;
92
}
93
94
}
// namespace detail
95
96
/**
97
* The normalising constant by convolution over the invariant load vector.
98
*
99
* @param S S[i][p], the minimal-support S-invariants, one row per invariant
100
* @param V the load vector S m0, one entry per invariant
101
* @param g g[p][i] is g_p(i), the product-form factor of i tokens in place p;
102
* its length bounds the marking of place p
103
*/
104
template
<
class
T>
105
T
spn_conv
(
const
std::vector<std::vector<long long>>& S,
const
std::vector<long long>& V,
106
const
std::vector<std::vector<T>>& g) {
107
if
(S.empty())
throw
InputError
(
"spn_conv: the net has no S-invariant to convolve over"
);
108
if
(S.size() != V.size())
109
throw
InputError
(
"spn_conv: one load-vector entry per invariant is required"
);
110
const
std::size_t n = g.size();
111
for
(std::size_t r = 0; r < S.size(); ++r) {
112
if
(S[r].size() != n)
113
throw
InputError
(
"spn_conv: the invariant matrix and g must agree on the place count"
);
114
for
(std::size_t p = 0; p < n; ++p)
115
if
(S[r][p] < 0)
116
throw
InputError
(
"spn_conv: an S-invariant has a negative weight, so the residual "
117
"recursion has no monotone bound on the marking"
);
118
}
119
std::map<std::pair<std::size_t, std::vector<long long>>, T> memo;
120
return
detail::spn_conv_rec(n, V, S, g, memo);
121
}
122
123
/** Convolve straight off the invariant basis `spn_sinvariants` returned. */
124
template
<
class
T>
125
T
spn_conv
(
const
SpnInvariants
& inv,
const
std::vector<std::vector<T>>& g) {
126
return
spn_conv
(inv.
S
, inv.
V
, g);
127
}
128
129
}
// namespace spn
130
}
// namespace line
131
132
#endif
// LINE_API_SPN_SPN_CONV_H
line::InputError::InputError
InputError(const std::string &what)
Definition
error.h:39
error.h
The exception types the port throws.
line::spn
Definition
spn_conv.h:57
line::spn::spn_conv
T spn_conv(const std::vector< std::vector< long long > > &S, const std::vector< long long > &V, const std::vector< std::vector< T > > &g)
The normalising constant by convolution over the invariant load vector.
Definition
spn_conv.h:105
line
Definition
aoi_dist2ph.h:52
number.h
Number-type abstraction for the templated API port.
spn_sinvariants.h
Minimal-support S-invariants (P-invariants) of a stochastic Petri net, and the load vector V = S m0.
line::num_traits
Definition
number.h:111
line::spn::SpnInvariants
The invariant basis of a net, in place-level coordinates.
Definition
spn_sinvariants.h:51
line::spn::SpnInvariants::S
std::vector< std::vector< long long > > S
S[i][p]: weight of place p in minimal-support invariant i.
Definition
spn_sinvariants.h:55
line::spn::SpnInvariants::V
std::vector< long long > V
V = S m0, the load vector.
Definition
spn_sinvariants.h:57
include
line
api
spn
spn_conv.h
Generated by
1.18.0