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/PTN_EngineImp.h" 22 : #include "PTN_Engine/Executor/ActionsExecutorFactory.h" 23 : #include "PTN_Engine/Utilities/LockWeakPtr.h" 24 : #include <algorithm> 25 : 26 : namespace ptne 27 : { 28 : using namespace std; 29 : using enum PTN_Engine::ACTIONS_THREAD_OPTION; 30 : 31 71 : PTN_EngineImp::PTN_EngineImp(PTN_Engine::ACTIONS_THREAD_OPTION actionsThreadOption) 32 71 : : m_actionsThreadOption(actionsThreadOption) 33 71 : , m_actionsExecutor(ActionsExecutorFactory::createExecutor(actionsThreadOption)) 34 142 : , m_eventLoop(*this) 35 : { 36 71 : } 37 : 38 71 : PTN_EngineImp::~PTN_EngineImp() 39 : { 40 71 : stop(); 41 71 : } 42 : 43 1 : void PTN_EngineImp::clearInputPlaces() 44 : { 45 1 : m_places.clearInputPlaces(); 46 1 : m_newInputReceived = false; 47 1 : } 48 : 49 1 : void PTN_EngineImp::clearNet() 50 : { 51 1 : if (isEventLoopRunning()) 52 : { 53 0 : throw PTN_Exception("Cannot clear net while the event loop is running."); 54 : } 55 1 : m_transitions.clear(); 56 1 : m_places.clear(); 57 1 : } 58 : 59 143 : void PTN_EngineImp::createTransition(const TransitionProperties &transitionProperties) 60 : { 61 285 : createTransition(transitionProperties.name, transitionProperties.activationArcs, 62 142 : transitionProperties.destinationArcs, transitionProperties.inhibitorArcs, 63 285 : !transitionProperties.additionalConditionsNames.empty() ? 64 8 : m_conditions.getItems(transitionProperties.additionalConditionsNames) : 65 135 : createAnonymousConditions(transitionProperties.additionalConditions), 66 143 : transitionProperties.requireNoActionsInExecution); 67 140 : } 68 : 69 188 : void PTN_EngineImp::createPlace(PlaceProperties placeProperties) 70 : { 71 188 : ActionFunction onEnterAction = placeProperties.onEnterAction; 72 188 : if (!placeProperties.onEnterActionFunctionName.empty()) 73 : { 74 8 : placeProperties.onEnterAction = m_actions.getItem(placeProperties.onEnterActionFunctionName); 75 : } 76 : 77 187 : ActionFunction onExitAction = placeProperties.onExitAction; 78 187 : if (!placeProperties.onExitActionFunctionName.empty()) 79 : { 80 0 : placeProperties.onExitAction = m_actions.getItem(placeProperties.onExitActionFunctionName); 81 : } 82 : 83 187 : auto place = make_shared<Place>(placeProperties, m_actionsExecutor); 84 187 : m_places.insert(place); 85 192 : } 86 : 87 98 : bool PTN_EngineImp::isEventLoopRunning() const 88 : { 89 98 : return m_eventLoop.isRunning(); 90 : } 91 : 92 168 : void PTN_EngineImp::stop() noexcept 93 : { 94 168 : m_eventLoop.stop(); 95 168 : } 96 : 97 11 : void PTN_EngineImp::registerAction(const string &name, const ActionFunction &action) 98 : { 99 11 : m_actions.addItem(name, action); 100 7 : } 101 : 102 12 : void PTN_EngineImp::registerCondition(const string &name, const ConditionFunction &condition) 103 : { 104 12 : m_conditions.addItem(name, condition); 105 10 : } 106 : 107 181 : size_t PTN_EngineImp::getNumberOfTokens(const string &place) const 108 : { 109 181 : return m_places.getNumberOfTokens(place); 110 : } 111 : 112 2474 : void PTN_EngineImp::incrementInputPlace(const string &place) 113 : { 114 2474 : m_places.incrementInputPlace(place); 115 2473 : m_newInputReceived = true; 116 2473 : m_eventLoop.notifyNewEvent(); 117 2473 : } 118 : 119 63 : void PTN_EngineImp::setActionsThreadOption(const PTN_Engine::ACTIONS_THREAD_OPTION actionsThreadOption) 120 : { 121 63 : if (isEventLoopRunning()) 122 : { 123 4 : throw PTN_Exception("Cannot change actions thread option while the event loop is running."); 124 : } 125 : 126 59 : unique_lock actionsThreadOptionGuard(m_actionsThreadOptionMutex); 127 : 128 59 : if (m_actionsThreadOption == actionsThreadOption) 129 : { 130 56 : return; 131 : } 132 : 133 3 : m_actionsExecutor = ActionsExecutorFactory::createExecutor(actionsThreadOption); 134 3 : m_actionsThreadOption = actionsThreadOption; 135 : 136 3 : m_places.setActionsExecutor(m_actionsExecutor); 137 59 : } 138 : 139 46 : PTN_Engine::ACTIONS_THREAD_OPTION PTN_EngineImp::getActionsThreadOption() const 140 : { 141 46 : shared_lock actionsThreadOptionGuard(m_actionsThreadOptionMutex); 142 46 : return m_actionsThreadOption; 143 46 : } 144 : 145 0 : void PTN_EngineImp::printState(ostream &o) const 146 : { 147 0 : m_places.printState(o); 148 0 : } 149 : 150 39 : void PTN_EngineImp::execute(const bool log, ostream &o) 151 : { 152 39 : m_eventLoop.start(log, o); 153 39 : } 154 : 155 806712 : bool PTN_EngineImp::executeInt(const bool log, ostream &o) 156 : { 157 806712 : bool firedAtLeastOneTransition = false; 158 806712 : setNewInputReceived(false); 159 : 160 806712 : if (log) 161 : { 162 0 : printState(o); 163 : } 164 : 165 1633171 : for (const auto &transition : enabledTransitions()) 166 : { 167 1652918 : if (auto enabledTransition = lockWeakPtr(transition)) 168 : { 169 826459 : firedAtLeastOneTransition |= enabledTransition->execute(); 170 826459 : } 171 806712 : } 172 806712 : return firedAtLeastOneTransition; 173 : } 174 : 175 4510 : bool PTN_EngineImp::getNewInputReceived() const 176 : { 177 4510 : return m_newInputReceived; 178 : } 179 : 180 806712 : void PTN_EngineImp::setNewInputReceived(const bool newInputReceived) 181 : { 182 806712 : m_newInputReceived = newInputReceived; 183 806712 : } 184 : 185 807717 : vector<weak_ptr<Transition>> PTN_EngineImp::enabledTransitions() const 186 : { 187 807717 : return m_transitions.collectEnabledTransitionsRandomly(); 188 : } 189 : 190 1 : void PTN_EngineImp::setEventLoopSleepDuration(const PTN_Engine::EventLoopSleepDuration sleepDuration) 191 : { 192 1 : m_eventLoop.setSleepDuration(sleepDuration); 193 1 : } 194 : 195 2 : PTN_Engine::EventLoopSleepDuration PTN_EngineImp::getEventLoopSleepDuration() const 196 : { 197 2 : return m_eventLoop.getSleepDuration(); 198 : } 199 : 200 19 : void PTN_EngineImp::addArc(const ArcProperties &arcProperties) const 201 : { 202 19 : if (isEventLoopRunning()) 203 : { 204 0 : throw PTN_Exception("Cannot add arc while the event loop is running."); 205 : } 206 : 207 19 : if (!m_places.contains(arcProperties.placeName)) 208 : { 209 0 : throw PTN_Exception("The place " + arcProperties.placeName + 210 0 : " must already exist in order to link to an arc."); 211 : } 212 19 : auto spPlace = m_places.getPlace(arcProperties.placeName); 213 : 214 19 : if (!m_transitions.contains(arcProperties.transitionName)) 215 : { 216 0 : throw PTN_Exception("The transition " + arcProperties.transitionName + 217 0 : " must already exist in order to link to an arc."); 218 : } 219 : 220 19 : auto spTransition = m_transitions.getTransition(arcProperties.transitionName); 221 19 : spTransition->addArc(spPlace, arcProperties.type, arcProperties.weight); 222 19 : } 223 : 224 2 : void PTN_EngineImp::removeArc(const ArcProperties &arcProperties) const 225 : { 226 2 : if (isEventLoopRunning()) 227 : { 228 0 : throw PTN_Exception("Cannot remove arc while the event loop is running."); 229 : } 230 : 231 2 : if (!m_places.contains(arcProperties.placeName)) 232 : { 233 1 : throw PTN_Exception("The place " + arcProperties.placeName + 234 2 : " must already exist in order to unlink an arc."); 235 : } 236 1 : auto spPlace = m_places.getPlace(arcProperties.placeName); 237 : 238 1 : if (!m_transitions.contains(arcProperties.transitionName)) 239 : { 240 0 : throw PTN_Exception("The transition " + arcProperties.transitionName + 241 0 : " must already exist in order to unlink an arc."); 242 : } 243 : 244 1 : auto spTransition = m_transitions.getTransition(arcProperties.transitionName); 245 1 : spTransition->removeArc(spPlace, arcProperties.type); 246 1 : } 247 : 248 12 : vector<PlaceProperties> PTN_EngineImp::getPlacesProperties() const 249 : { 250 12 : return m_places.getPlacesProperties(); 251 : } 252 : 253 13 : vector<TransitionProperties> PTN_EngineImp::getTransitionsProperties() const 254 : { 255 13 : return m_transitions.getTransitionsProperties(); 256 : } 257 : 258 : // Private 259 : 260 142 : void PTN_EngineImp::createTransition(const string &name, 261 : const vector<ArcProperties> &activationArcs, 262 : const vector<ArcProperties> &destinationArcs, 263 : const vector<ArcProperties> &inhibitorArcs, 264 : const vector<pair<string, ConditionFunction>> &additionalConditions, 265 : const bool requireNoActionsInExecution) 266 : { 267 : // if a transition with this name already exists in the net, throw an exception 268 142 : if (m_transitions.contains(name)) 269 : { 270 1 : throw PTN_Exception("Cannot create transition that already exists. Name: " + name); 271 : } 272 : 273 800 : auto getArcsFromArcsProperties = [this](const vector<ArcProperties> &arcProperties) 274 : { 275 423 : vector<Arc> arcs; 276 800 : for (const auto &arcProperty : arcProperties) 277 : { 278 377 : arcs.emplace_back(m_places.getPlace(arcProperty.placeName), arcProperty.weight); 279 : } 280 423 : return arcs; 281 0 : }; 282 : 283 143 : m_transitions.insert(make_shared<Transition>(name, getArcsFromArcsProperties(activationArcs), 284 283 : getArcsFromArcsProperties(destinationArcs), 285 283 : getArcsFromArcsProperties(inhibitorArcs), additionalConditions, 286 : requireNoActionsInExecution)); 287 140 : } 288 : 289 : vector<pair<string, ConditionFunction>> 290 135 : PTN_EngineImp::createAnonymousConditions(const vector<ConditionFunction> &conditions) const 291 : { 292 135 : vector<pair<string, ConditionFunction>> anonymousConditionsVector; 293 135 : ranges::transform(conditions, back_inserter(anonymousConditionsVector), 294 22 : [](const auto &condition) { return pair<string, ConditionFunction>("", condition); }); 295 135 : return anonymousConditionsVector; 296 0 : } 297 : 298 : } // namespace ptne