Line data Source code
1 : /*
2 : * This file is part of PTN Engine
3 : *
4 : * Copyright (c) 2017 Eduardo Valgôde
5 : * Copyright (c) 2021 Kale Evans
6 : * Copyright (c) 2024 Eduardo Valgôde
7 : *
8 : * Licensed under the Apache License, Version 2.0 (the "License");
9 : * you may not use this file except in compliance with the License.
10 : * You may obtain a copy of the License at
11 : *
12 : * http://www.apache.org/licenses/LICENSE-2.0
13 : *
14 : * Unless required by applicable law or agreed to in writing, software
15 : * distributed under the License is distributed on an "AS IS" BASIS,
16 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 : * See the License for the specific language governing permissions and
18 : * limitations under the License.
19 : */
20 :
21 : #include "PTN_Engine/Transition.h"
22 : #include "PTN_Engine/PTN_Exception.h"
23 : #include "PTN_Engine/Place.h"
24 : #include "PTN_Engine/Utilities/DetectRepeated.h"
25 : #include "PTN_Engine/Utilities/LockWeakPtr.h"
26 : #include <algorithm>
27 : #include <array>
28 : #include <mutex>
29 : #include <vector>
30 :
31 : namespace ptne
32 : {
33 : using namespace std;
34 :
35 182 : Transition::~Transition() = default;
36 :
37 186 : Transition::Transition(const string &name,
38 : const vector<Arc> &activationArcs,
39 : const vector<Arc> &destinationArcs,
40 : const vector<Arc> &inhibitorArcs,
41 : const vector<pair<string, ConditionFunction>> &additionalActivationConditions,
42 186 : const bool requireNoActionsInExecution)
43 186 : : m_name(name)
44 186 : , m_activationArcs(activationArcs)
45 186 : , m_destinationArcs(destinationArcs)
46 186 : , m_additionalActivationConditions(additionalActivationConditions)
47 186 : , m_inhibitorArcs(inhibitorArcs)
48 186 : , m_requireNoActionsInExecution(requireNoActionsInExecution)
49 : {
50 555 : auto getPlacesFromArcs = [](const vector<Arc> &arcs)
51 : {
52 555 : vector<WeakPtrPlace> places;
53 958 : ranges::transform(arcs, back_inserter(places), [](const auto &arc) { return arc.place; });
54 555 : return places;
55 0 : };
56 :
57 187 : utility::detectRepeated<Place, ActivationPlaceRepetitionException>(getPlacesFromArcs(activationArcs));
58 186 : utility::detectRepeated<Place, DestinationPlaceRepetitionException>(getPlacesFromArcs(destinationArcs));
59 185 : utility::detectRepeated<Place, InhibitorPlaceRepetitionException>(getPlacesFromArcs(inhibitorArcs));
60 :
61 549 : auto validateWeights = [](const vector<Arc> &arcs)
62 : {
63 946 : if (ranges::find_if(arcs, [](const auto &arc) { return arc.weight == 0; }) != arcs.cend())
64 : {
65 1 : throw ZeroValueWeightException();
66 : }
67 548 : };
68 :
69 183 : validateWeights(activationArcs);
70 183 : validateWeights(destinationArcs);
71 183 : validateWeights(inhibitorArcs);
72 202 : }
73 :
74 1182 : string Transition::getName() const
75 : {
76 1182 : shared_lock guard(m_mutex);
77 2364 : return m_name;
78 1182 : }
79 :
80 826478 : bool Transition::execute()
81 : {
82 826478 : unique_lock guard(m_mutex);
83 826478 : bool result = false;
84 :
85 826478 : blockStartingOnEnterActions(true);
86 :
87 826478 : if (!isActive())
88 : {
89 22006 : result = false;
90 : }
91 : else
92 : {
93 804471 : performTransit();
94 804471 : result = true;
95 : }
96 :
97 826477 : blockStartingOnEnterActions(false);
98 :
99 826477 : return result;
100 826478 : }
101 :
102 2248599 : bool Transition::isEnabled() const
103 : {
104 2248599 : shared_lock guard(m_mutex);
105 4497198 : return isEnabledInternal();
106 2248599 : }
107 :
108 3075077 : bool Transition::isEnabledInternal() const
109 : {
110 3075077 : if (!checkInhibitorPlaces())
111 : {
112 600030 : return false;
113 : }
114 :
115 2475046 : if (!checkActivationPlaces())
116 : {
117 822304 : return false;
118 : }
119 :
120 1652742 : return true;
121 : }
122 :
123 826478 : bool Transition::isActive() const
124 : {
125 1650748 : return isEnabledInternal() && (!m_requireNoActionsInExecution || noActionsInExecution()) &&
126 1650747 : checkAdditionalConditions();
127 : }
128 :
129 24 : vector<Arc> Transition::getActivationArcs() const
130 : {
131 24 : shared_lock guard(m_mutex);
132 48 : return m_activationArcs;
133 24 : }
134 :
135 25 : vector<Arc> Transition::getDestinationArcs() const
136 : {
137 25 : shared_lock guard(m_mutex);
138 50 : return m_destinationArcs;
139 25 : }
140 :
141 1 : vector<pair<string, ConditionFunction>> Transition::getAdditionalActivationConditions() const
142 : {
143 1 : shared_lock guard(m_mutex);
144 2 : return m_additionalActivationConditions;
145 1 : }
146 :
147 24 : vector<Arc> Transition::getInhibitorArcs() const
148 : {
149 24 : shared_lock guard(m_mutex);
150 48 : return m_inhibitorArcs;
151 24 : }
152 :
153 3075077 : bool Transition::checkInhibitorPlaces() const
154 : {
155 600087 : auto numberOfTokensGreaterThan0 = [](const auto &inhibitorArc)
156 : {
157 600088 : SharedPtrPlace spInhibitorArc = lockWeakPtr(inhibitorArc.place);
158 1200172 : return spInhibitorArc->getNumberOfTokens() > 0;
159 600086 : };
160 :
161 3075077 : if (ranges::find_if(m_inhibitorArcs, numberOfTokensGreaterThan0) != m_inhibitorArcs.end())
162 : {
163 600030 : return false;
164 : }
165 2475046 : return true;
166 : }
167 :
168 18 : TransitionProperties Transition::getTransitionProperties() const
169 : {
170 18 : shared_lock guard(m_mutex);
171 :
172 18 : TransitionProperties transitionProperties;
173 :
174 36 : auto getAdditionalConditionsNames = [this]()
175 : {
176 18 : vector<string> additionalActivationConditionNames;
177 19 : for (const auto &[additionalActivationConditionName, _] : m_additionalActivationConditions)
178 : {
179 1 : additionalActivationConditionNames.push_back(additionalActivationConditionName);
180 : }
181 18 : return additionalActivationConditionNames;
182 0 : };
183 :
184 36 : auto getAdditionalConditions = [this]()
185 : {
186 18 : vector<ConditionFunction> additionalActivationConditions;
187 19 : for (const auto &[_, additionalActivationCondition] : m_additionalActivationConditions)
188 : {
189 1 : additionalActivationConditions.push_back(additionalActivationCondition);
190 : }
191 18 : return additionalActivationConditions;
192 0 : };
193 :
194 18 : transitionProperties.additionalConditionsNames = getAdditionalConditionsNames();
195 :
196 68 : auto getProperties = [this](const vector<Arc> &arcs, ArcProperties::Type type)
197 : {
198 54 : vector<ArcProperties> arcsProperties;
199 68 : for (const auto &arc : arcs)
200 : {
201 14 : auto spPlace = lockWeakPtr(arc.place);
202 14 : arcsProperties.emplace_back(arc.weight, spPlace->getName(), getName(), type);
203 14 : }
204 54 : return arcsProperties;
205 0 : };
206 18 : transitionProperties.additionalConditions = getAdditionalConditions();
207 :
208 18 : transitionProperties.activationArcs = getProperties(getActivationArcs(), ArcProperties::Type::ACTIVATION);
209 18 : transitionProperties.destinationArcs = getProperties(getDestinationArcs(), ArcProperties::Type::DESTINATION);
210 18 : transitionProperties.inhibitorArcs = getProperties(getInhibitorArcs(), ArcProperties::Type::INHIBITOR);
211 18 : transitionProperties.name = getName();
212 18 : transitionProperties.requireNoActionsInExecution = m_requireNoActionsInExecution;
213 :
214 36 : return transitionProperties;
215 18 : }
216 :
217 58 : void Transition::addArc(const shared_ptr<Place> &place, const ArcProperties::Type type, const size_t weight)
218 : {
219 58 : unique_lock guard(m_mutex);
220 :
221 175 : auto addArcTo = [&place, weight](auto &placesContainer)
222 : {
223 69 : auto sameNameAs = [&place](const auto &arc)
224 10 : { return lockWeakPtr(arc.place)->getName() == place->getName(); };
225 :
226 59 : if (ranges::find_if(placesContainer, sameNameAs) != placesContainer.cend())
227 : {
228 1 : throw PTN_Exception("Arc already exists");
229 : }
230 58 : placesContainer.push_back({ place, weight });
231 58 : };
232 :
233 : using enum ArcProperties::Type;
234 58 : switch (type)
235 : {
236 0 : default:
237 : {
238 0 : throw PTN_Exception("Unexpected type");
239 : }
240 36 : case ACTIVATION:
241 : {
242 36 : addArcTo(m_activationArcs);
243 35 : break;
244 : }
245 1 : case BIDIRECTIONAL:
246 : {
247 1 : addArcTo(m_activationArcs);
248 1 : addArcTo(m_destinationArcs);
249 1 : break;
250 : }
251 14 : case DESTINATION:
252 : {
253 14 : addArcTo(m_destinationArcs);
254 14 : break;
255 : }
256 7 : case INHIBITOR:
257 : {
258 7 : addArcTo(m_inhibitorArcs);
259 7 : break;
260 : }
261 : }
262 58 : }
263 :
264 7 : void Transition::removeArc(const shared_ptr<Place> &place, const ArcProperties::Type type)
265 : {
266 7 : unique_lock guard(m_mutex);
267 :
268 10 : auto removePlaceFrom = [&place](auto &placesContainer)
269 : {
270 11 : auto sameNameAs = [&place](const auto &arc)
271 4 : { return lockWeakPtr(arc.place)->getName() == place->getName(); };
272 :
273 7 : auto it = ranges::find_if(placesContainer, sameNameAs);
274 7 : if (it != placesContainer.cend())
275 : {
276 4 : placesContainer.erase(it);
277 : }
278 : else
279 : {
280 3 : throw PTN_Exception("Cannot remove palce " + place->getName());
281 : }
282 4 : };
283 :
284 : using enum ArcProperties::Type;
285 7 : switch (type)
286 : {
287 0 : default:
288 : {
289 0 : throw PTN_Exception("Unexpected type");
290 : }
291 3 : case ACTIVATION:
292 : {
293 3 : removePlaceFrom(m_activationArcs);
294 2 : break;
295 : }
296 0 : case BIDIRECTIONAL:
297 : {
298 0 : removePlaceFrom(m_activationArcs);
299 0 : removePlaceFrom(m_destinationArcs);
300 0 : break;
301 : }
302 2 : case DESTINATION:
303 : {
304 2 : removePlaceFrom(m_destinationArcs);
305 1 : break;
306 : }
307 2 : case INHIBITOR:
308 : {
309 2 : removePlaceFrom(m_inhibitorArcs);
310 1 : break;
311 : }
312 : }
313 7 : }
314 :
315 2475046 : bool Transition::checkActivationPlaces() const
316 : {
317 4934496 : for (const Arc &activationArc : m_activationArcs)
318 : {
319 3281754 : const WeakPtrPlace &activationPlace = activationArc.place;
320 3281754 : const size_t activationWeight = activationArc.weight;
321 :
322 3281754 : SharedPtrPlace spPlace = lockWeakPtr(activationPlace);
323 :
324 3281754 : if (spPlace->getNumberOfTokens() < activationWeight)
325 : {
326 822304 : return false;
327 : }
328 3281754 : }
329 1652742 : return true;
330 : }
331 :
332 824270 : bool Transition::checkAdditionalConditions() const
333 : {
334 824289 : for (const auto &[name, activationCondition] : m_additionalActivationConditions)
335 : {
336 19818 : if (!activationCondition)
337 : {
338 0 : throw PTN_Exception("Invalid activation condition " + name);
339 : }
340 : else
341 : {
342 19818 : if (!activationCondition())
343 : {
344 19799 : return false;
345 : }
346 : }
347 : }
348 804471 : return true;
349 : }
350 :
351 3 : bool Transition::noActionsInExecution() const
352 : {
353 4 : for (const Arc &activationArc : m_activationArcs)
354 : {
355 3 : const WeakPtrPlace &activationPlace = activationArc.place;
356 :
357 3 : SharedPtrPlace spPlace = lockWeakPtr(activationPlace);
358 3 : if (spPlace->isOnEnterActionInExecution())
359 : {
360 2 : return false;
361 : }
362 3 : }
363 1 : return true;
364 : }
365 :
366 804471 : void Transition::performTransit() const
367 : {
368 804471 : exitActivationPlaces();
369 804471 : enterDestinationPlaces();
370 804471 : }
371 :
372 804471 : void Transition::exitActivationPlaces() const
373 : {
374 2011179 : for (const Arc &activationArc : m_activationArcs)
375 : {
376 1206708 : const WeakPtrPlace &activationPlace = activationArc.place;
377 1206708 : const size_t activationWeight = activationArc.weight;
378 :
379 2413416 : if (SharedPtrPlace spPlace = lockWeakPtr(activationPlace))
380 : {
381 1206708 : spPlace->exitPlace(activationWeight);
382 1206708 : }
383 : }
384 804471 : }
385 :
386 804471 : void Transition::enterDestinationPlaces() const
387 : {
388 1613354 : for (const Arc &destinationArc : m_destinationArcs)
389 : {
390 808883 : const WeakPtrPlace &destinationPlace = destinationArc.place;
391 808883 : const size_t destinationWeight = destinationArc.weight;
392 :
393 1617766 : if (SharedPtrPlace spPlace = lockWeakPtr(destinationPlace))
394 : {
395 808883 : spPlace->enterPlace(destinationWeight);
396 808883 : }
397 : }
398 804471 : }
399 :
400 1652955 : void Transition::blockStartingOnEnterActions(const bool value) const
401 : {
402 1652955 : if (!m_requireNoActionsInExecution)
403 : {
404 1652949 : return;
405 : }
406 :
407 12 : for (const Arc &activationArc : m_activationArcs)
408 : {
409 6 : const WeakPtrPlace &activationPlace = activationArc.place;
410 12 : if (SharedPtrPlace spPlace = lockWeakPtr(activationPlace))
411 : {
412 6 : spPlace->blockStartingOnEnterActions(value);
413 6 : }
414 : }
415 : }
416 : } // namespace ptne
|