125 const std::vector<double>& init = std::vector<double>()) {
126 std::vector<std::size_t> places, transitions;
127 for (std::size_t i = 1; i <=
sn.nodes.size(); ++i) {
131 if (places.empty() || transitions.empty())
132 throw InputError(
"spn_sinvariants: the model holds no Place or no Transition node");
133 const std::size_t R =
sn.nclasses;
134 const std::size_t P = places.size();
135 const std::size_t n = P * R;
141 std::vector<std::vector<long long>> C(n);
142 std::size_t ncols = 0;
143 for (std::size_t t = 0; t < transitions.size(); ++t) {
144 const typename std::map<std::size_t, qn::TransitionParam<T>>::const_iterator it =
145 sn.transparam.find(transitions[t]);
146 if (it ==
sn.transparam.end())
continue;
148 for (std::size_t m = 0; m < tp.
nmodes; ++m) {
151 for (std::size_t pp = 0; pp < P; ++pp) {
152 const std::size_t q = places[pp] - 1;
153 for (std::size_t k = 0; k < R; ++k) {
154 double pre = 0, post = 0;
155 if (en && q < en->rows() && k < en->cols())
157 if (fi && q < fi->rows() && k < fi->cols())
159 C[pp * R + k].push_back(detail::spn_as_integer(post,
"a firing arc") -
160 detail::spn_as_integer(pre,
"an enabling arc"));
168 std::vector<std::vector<long long>> rows(n);
169 for (std::size_t p = 0; p < n; ++p) {
170 rows[p].assign(ncols + n, 0);
171 for (std::size_t c = 0; c < ncols; ++c) rows[p][c] = C[p][c];
172 rows[p][ncols + p] = 1;
174 for (std::size_t c = 0; c < ncols; ++c) {
175 std::vector<std::vector<long long>> next;
176 for (std::size_t r = 0; r < rows.size(); ++r)
177 if (rows[r][c] == 0) next.push_back(rows[r]);
178 for (std::size_t a = 0; a < rows.size(); ++a) {
179 if (rows[a][c] <= 0)
continue;
180 for (std::size_t b = 0; b < rows.size(); ++b) {
181 if (rows[b][c] >= 0)
continue;
182 const long long pa = rows[a][c], nb = -rows[b][c];
183 const long long d = detail::spn_gcd(pa, nb);
184 const long long fa = nb / d, fb = pa / d;
185 std::vector<long long> combo(ncols + n, 0);
187 for (std::size_t k = 0; k < combo.size(); ++k) {
188 combo[k] = fa * rows[a][k] + fb * rows[b][k];
189 g = detail::spn_gcd(g, combo[k]);
192 for (std::size_t k = 0; k < combo.size(); ++k) combo[k] /= g;
193 bool nonzero =
false;
194 for (std::size_t k = 0; k < n; ++k) nonzero = nonzero || combo[ncols + k] != 0;
195 if (nonzero) next.push_back(combo);
200 std::vector<std::vector<long long>> keep;
201 for (std::size_t r = 0; r < next.size(); ++r) {
202 bool dominated =
false;
203 for (std::size_t s = 0; s < next.size() && !dominated; ++s) {
204 if (s == r)
continue;
205 if (!detail::spn_support_subset(next[s], next[r], ncols, n))
continue;
206 const bool same = detail::spn_support_equal(next[s], next[r], ncols, n);
207 if (!same || s < r) dominated =
true;
209 if (!dominated) keep.push_back(next[r]);
216 for (std::size_t r = 0; r < rows.size(); ++r) {
218 for (std::size_t k = 0; k < n; ++k) nonneg = nonneg && rows[r][ncols + k] >= 0;
219 if (!nonneg)
continue;
220 std::vector<long long> y(n, 0);
221 for (std::size_t k = 0; k < n; ++k) y[k] = rows[r][ncols + k];
229 if (init.size() != n)
230 throw InputError(
"spn_sinvariants: init must hold one token count per place level");
231 for (std::size_t l = 0; l < n; ++l)
232 out.m0[l] = detail::spn_as_integer(init[l],
"an initial marking");
234 for (std::size_t k = 0; k < R; ++k) {
235 const double njobs = sn.classes[k].population;
236 if (!std::isfinite(njobs))
237 throw UnsupportedError(ErrorKind{
"OpenClass"},
"spn_sinvariants: class " + std::to_string(k + 1) +
238 " is open, so the net has no finite load vector");
239 const std::size_t ref_node = sn.station_to_node[sn.classes[k].refstat - 1];
240 for (std::size_t pp = 0; pp < P; ++pp)
241 if (places[pp] == ref_node)
242 out.m0[pp * R + k] += detail::spn_as_integer(njobs,
"a class population");
245 out.V.assign(out.S.size(), 0);
246 for (std::size_t i = 0; i < out.S.size(); ++i)
247 for (std::size_t p = 0; p < n; ++p) out.V[i] += out.S[i][p] * out.m0[p];