111 const std::vector<double>& init = std::vector<double>()) {
112 std::vector<std::size_t> places, transitions;
113 for (std::size_t i = 1; i <=
sn.nodes.size(); ++i) {
117 if (places.empty() || transitions.empty())
118 throw InputError(
"spn_sinvariants: the model holds no Place or no Transition node");
119 const std::size_t n = places.size();
122 std::vector<std::vector<long long>> C(n);
123 std::size_t ncols = 0;
124 for (std::size_t p = 0; p < n; ++p) C[p].clear();
125 for (std::size_t t = 0; t < transitions.size(); ++t) {
126 const typename std::map<std::size_t, qn::TransitionParam<T>>::const_iterator it =
127 sn.transparam.find(transitions[t]);
128 if (it ==
sn.transparam.end())
continue;
130 for (std::size_t m = 0; m < tp.
nmodes; ++m) {
139 for (std::size_t p = 0; p < n; ++p) {
140 const std::size_t q = places[p] - 1;
141 double pre = 0, post = 0;
144 C[p].push_back(detail::spn_as_integer(post,
"a firing arc") -
145 detail::spn_as_integer(pre,
"an enabling arc"));
152 std::vector<std::vector<long long>> rows(n);
153 for (std::size_t p = 0; p < n; ++p) {
154 rows[p].assign(ncols + n, 0);
155 for (std::size_t c = 0; c < ncols; ++c) rows[p][c] = C[p][c];
156 rows[p][ncols + p] = 1;
158 for (std::size_t c = 0; c < ncols; ++c) {
159 std::vector<std::vector<long long>> next;
160 for (std::size_t r = 0; r < rows.size(); ++r)
161 if (rows[r][c] == 0) next.push_back(rows[r]);
162 for (std::size_t a = 0; a < rows.size(); ++a) {
163 if (rows[a][c] <= 0)
continue;
164 for (std::size_t b = 0; b < rows.size(); ++b) {
165 if (rows[b][c] >= 0)
continue;
166 const long long pa = rows[a][c], nb = -rows[b][c];
167 const long long d = detail::spn_gcd(pa, nb);
168 const long long fa = nb / d, fb = pa / d;
169 std::vector<long long> combo(ncols + n, 0);
171 for (std::size_t k = 0; k < combo.size(); ++k) {
172 combo[k] = fa * rows[a][k] + fb * rows[b][k];
173 g = detail::spn_gcd(g, combo[k]);
176 for (std::size_t k = 0; k < combo.size(); ++k) combo[k] /= g;
177 bool nonzero =
false;
178 for (std::size_t k = 0; k < n; ++k) nonzero = nonzero || combo[ncols + k] != 0;
179 if (nonzero) next.push_back(combo);
184 std::vector<std::vector<long long>> keep;
185 for (std::size_t r = 0; r < next.size(); ++r) {
186 bool dominated =
false;
187 for (std::size_t s = 0; s < next.size() && !dominated; ++s) {
188 if (s == r)
continue;
189 if (!detail::spn_support_subset(next[s], next[r], ncols, n))
continue;
190 const bool same = detail::spn_support_equal(next[s], next[r], ncols, n);
191 if (!same || s < r) dominated =
true;
193 if (!dominated) keep.push_back(next[r]);
200 for (std::size_t r = 0; r < rows.size(); ++r) {
202 for (std::size_t k = 0; k < n; ++k) nonneg = nonneg && rows[r][ncols + k] >= 0;
203 if (!nonneg)
continue;
204 std::vector<long long> y(n, 0);
205 for (std::size_t k = 0; k < n; ++k) y[k] = rows[r][ncols + k];
212 if (init.size() != n)
213 throw InputError(
"spn_sinvariants: init must hold one token count per place");
214 for (std::size_t p = 0; p < n; ++p)
215 out.m0[p] = detail::spn_as_integer(init[p],
"an initial marking");
217 for (std::size_t r = 0; r < sn.classes.size(); ++r) {
218 const double njobs = sn.classes[r].population;
219 if (!std::isfinite(njobs))
220 throw UnsupportedError(
"spn_sinvariants: class " + std::to_string(r + 1) +
221 " is open, so the net has no finite load vector");
222 const std::size_t ref_node = sn.station_to_node[sn.classes[r].refstat - 1];
223 for (std::size_t p = 0; p < n; ++p)
224 if (places[p] == ref_node)
225 out.m0[p] += detail::spn_as_integer(njobs,
"a class population");
228 out.V.assign(out.S.size(), 0);
229 for (std::size_t i = 0; i < out.S.size(); ++i)
230 for (std::size_t p = 0; p < n; ++p) out.V[i] += out.S[i][p] * out.m0[p];