LCOV - code coverage report
Current view: top level - PTN_Engine - Transition.cpp (source / functions) Hit Total Coverage
Test: filtered_coverage.info Lines: 201 214 93.9 %
Date: 2024-05-26 15:41:39 Functions: 34 34 100.0 %

          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

Generated by: LCOV version 1.14