BPMN-OS
BPMN for optimization and simulation
Loading...
Searching...
No Matches
Engine.cpp
Go to the documentation of this file.
1#include "Engine.h"
2#include "Token.h"
3#include "StateMachine.h"
11#include <cassert>
12
13using namespace BPMNOS::Execution;
14
23
25{
26//std::cerr << "~Engine()" << std::endl;
27}
28
30 if ( token_ptr.has_value() && token_ptr->expired() ) {
31 // relevant token no longer exists, skip command
32 return;
33 }
34
35 if ( stateMachine_ptr.has_value() && stateMachine_ptr->expired() ) {
36 // relevant state machine no longer exists, skip command
37 return;
38 }
39
40 function();
41}
42
44 terminated = false;
45 commands.clear();
46 // create initial system state
47 systemState = std::make_unique<SystemState>(this, scenario);
48/*
49 if ( conditionalEventObserver ) {
50 removeSubscriber(conditionalEventObserver.get(), Observable::Type::DataUpdate);
51 }
52 conditionalEventObserver = std::make_unique<ConditionalEventObserver>(systemState.get());
53 addSubscriber(conditionalEventObserver.get(), Observable::Type::DataUpdate);
54*/
56
57 // advance all tokens in system state
58 while ( !terminated && advance() ) {
59//std::cerr << ".";
60 if ( !systemState->isAlive() ) {
61//std::cerr << "dead" << std::endl;
62 break;
63 }
64 if ( systemState->getTime() > timeout ) {
65//std::cerr << "timeout" << std::endl;
66 break;
67 }
68 }
69
70 // get final objective value
71 return systemState->getObjective();
72// std::cout << "Objective (maximization): " << (float)objective << std::endl;
73// std::cout << "Objective (minimization): " << -(float)objective << std::endl;
74}
75
77 // add all new instances and advance tokens
79 // it is assumed that at least one clock tick or termination event is processed to ensure that
80 // each instance is only added once
81
82 while ( commands.size() ) {
83//std::cerr << "execute" << std::endl;
84 auto command = std::move(commands.front());
85 commands.pop_front();
86 command.execute();
87 }
88
89 // fetch and process all events
90 while ( auto event = fetchEvent(systemState.get()) ) {
91//std::cerr << "*";
92 notify(event.get());
93 event->processBy(this);
94
95 while ( commands.size() ) {
96 commands.front().execute();
97 commands.pop_front();
98 }
99
100 if ( event->is<ClockTickEvent>() ) {
101//std::cerr << "ClockTick" << std::endl;
102 // exit loop to resume
103 return true;
104 }
105
106 if ( event->is<TerminationEvent>() ) {
107 // exit loop to terminate
108 return false;
109 }
110 }
111
112 throw std::runtime_error("Engine: unexpected absence of event");
113}
114
116 for (auto& [process,status,data] : systemState->getInstantiations() ) {
117 if ( !process->isExecutable ) {
118 throw std::runtime_error("Engine: process '" + process->id + "' is not executable");
119 }
120 if ( !data[Model::ExtensionElements::Index::Instance].has_value() ) {
121 throw std::runtime_error("Engine: instance of process '" + process->id + "' has no id");
122 }
123 if ( !status[Model::ExtensionElements::Index::Timestamp].has_value() ) {
124 throw std::runtime_error("Engine: instance of process '" + process->id + "' has no timestamp");
125 }
126 systemState->instantiationCounter++;
127 systemState->instances.push_back(std::make_shared<StateMachine>(systemState.get(),process,std::move(data)));
128 // run instance and advance token
129 systemState->instances.back()->run(std::move(status));
130 }
131}
132
134//std::cerr << "deleteInstance" << std::endl;
135 erase_ptr<StateMachine>(systemState->instances,instance);
136}
137
138void Engine::process(const ReadyEvent* event) {
139//std::cerr << "ReadyEvent " << event.token->node->id << std::endl;
140 Token* token = const_cast<Token*>(event->token);
142 systemState->tokensAwaitingReadyEvent.remove(token);
143
144 token->sequenceFlow = nullptr;
145 token->status.insert(token->status.end(), event->statusAttributes.begin(), event->statusAttributes.end());
146
147 if ( auto scope = token->node->represents<BPMN::Scope>() ) {
148 const_cast<StateMachine*>(token->owner)->createChild(token, scope, event->dataAttributes);
149 }
150 commands.emplace_back(std::bind(&Token::advanceToReady,token), token);
151}
152
153void Engine::process(const EntryEvent* event) {
154//std::cerr << systemState->pendingEntryEvents.empty() << "EntryEvent " << event->token->jsonify().dump() << std::endl;
155 Token* token = const_cast<Token*>(event->token);
156 token->decisionRequest.reset();
159 token->occupySequentialPerformer();
160 }
161
162 // update token status
163 if ( event->entryStatus.has_value() ) {
164 token->status = event->entryStatus.value();
165 }
166
167 commands.emplace_back(std::bind(&Token::advanceToEntered,token), token);
168}
169
170void Engine::process(const ChoiceEvent* event) {
171//std::cerr << "ChoiceEvent " << event.token->node->id << std::endl;
172 Token* token = const_cast<Token*>(event->token);
173 token->decisionRequest.reset();
175 assert( token->node );
176 assert( token->node->represents<BPMNOS::Model::DecisionTask>() );
177
178 auto extensionElements = token->node->extensionElements->as<BPMNOS::Model::ExtensionElements>();
179 assert( extensionElements );
180 assert( extensionElements->choices.size() == event->choices.size() );
181 // apply choices
182 for (size_t i = 0; i < extensionElements->choices.size(); i++) {
183 extensionElements->attributeRegistry.setValue( extensionElements->choices[i]->attribute, token->status, *token->data, token->globals, event->choices[i] );
184 }
185
186 commands.emplace_back(std::bind(&Token::advanceToCompleted,token), token);
187}
188
190//std::cerr << "CompletionEvent " << event.token->node->id << std::endl;
191 Token* token = const_cast<Token*>(event->token);
192 systemState->tokensAwaitingCompletionEvent.remove(token);
193 // update token status
194 token->status = std::move(event->status);
195
196 commands.emplace_back(std::bind(&Token::advanceToCompleted,token), token);
197}
198
200 Token* token = const_cast<Token*>(event->token);
201 token->decisionRequest.reset();
203 assert( token->node );
204
205 auto message_ptr = event->message.lock();
206 assert( message_ptr );
207 Message* message = const_cast<Message*>(message_ptr.get());
208 // update token status
209 message->apply(token->node,token->getAttributeRegistry(),token->status,*token->data,token->globals);
210
212 notify(message);
213
214 erase_ptr<Message>(systemState->messages,message);
215
216 if ( message->waitingToken ) {
217 // send task is completed
218 systemState->messageAwaitingDelivery.erase( message->waitingToken );
219 commands.emplace_back(std::bind(&Token::advanceToCompleted,message->waitingToken), message->waitingToken);
220 }
221
222 commands.emplace_back(std::bind(&Token::advanceToCompleted,token), token);
223}
224
225void Engine::process(const ExitEvent* event) {
226//std::cerr << "ExitEvent: " << event->token->jsonify().dump() << std::endl;
227 Token* token = const_cast<Token*>(event->token);
228 token->decisionRequest.reset();
229
231 token->releaseSequentialPerformer();
232 }
233
234 // update token status
235 if ( event->exitStatus.has_value() ) {
236 token->status = event->exitStatus.value();
237 }
238
239 commands.emplace_back(std::bind(&Token::advanceToExiting,token), token);
240}
241
242void Engine::process(const ErrorEvent* event) {
243 Token* token = const_cast<Token*>(event->token);
244 commands.emplace_back(std::bind(&Token::advanceToFailed,token), token);
245}
246
247void Engine::process([[maybe_unused]] const ClockTickEvent* event) {
248//std::cerr << "ClockTickEvent " << std::endl;
249 systemState->incrementTimeBy(clockTick);
250 // trigger tokens awaiting timer
251 while ( !systemState->tokensAwaitingTimer.empty() ) {
252 auto it = systemState->tokensAwaitingTimer.begin();
253 auto [time, token_ptr] = *it;
254 if ( time > systemState->getTime() ) {
255 break;
256 }
257 auto token = token_ptr.lock();
258 assert( token );
259 notify(TimerEvent(token.get()));
260 commands.emplace_back(std::bind(&Token::advanceToCompleted,token.get()), token.get());
261 systemState->tokensAwaitingTimer.remove(token.get());
262 }
263}
264
265void Engine::process([[maybe_unused]] const TerminationEvent* event) {
266 terminated = true;
267}
268
269
271 return systemState->currentTime;
272}
273
275 return systemState.get();
276}
277
ReadyHandler readyHandler
Definition Engine.h:104
void process(const ReadyEvent *event)
Definition Engine.cpp:138
void deleteInstance(StateMachine *instance)
Method removing completed instance.
Definition Engine.cpp:133
BPMNOS::number clockTick
Timestep used to advance the current time by systemState.time += clockTick.
Definition Engine.h:100
ConditionalEventObserver conditionalEventObserver
Definition Engine.h:102
BPMNOS::number run(const BPMNOS::Model::Scenario *scenario, BPMNOS::number timeout=std::numeric_limits< BPMNOS::number >::max())
Runs a scenario as long as there is a token or new instantiations. Terminates when the time if the sy...
Definition Engine.cpp:43
std::unique_ptr< SystemState > systemState
Definition Engine.h:101
TaskCompletionHandler taskCompletionHandler
Definition Engine.h:105
std::list< Command > commands
List of commands to be executed.
Definition Engine.h:94
const SystemState * getSystemState()
Returns a pointer to the system state.
Definition Engine.cpp:274
BPMNOS::number getCurrentTime()
Returns the timestamp the engine is in.
Definition Engine.cpp:270
void addInstances()
Method adding all new instances and advancing tokens as much as possible.
Definition Engine.cpp:115
ScenarioUpdater scenarioUpdater
Definition Engine.h:103
void subscribe(EventDispatcher *eventDispatcher)
std::shared_ptr< Event > fetchEvent(SystemState *systemState)
void apply(const BPMN::FlowNode *node, const BPMNOS::Model::AttributeRegistry &attributeRegistry, BPMNOS::Values &status, DataType &data, BPMNOS::Values &globals) const
Updates the status at a node based on the message content.
Definition Message.cpp:92
void notify(const Observable *observable) const
Definition Notifier.cpp:10
void addSubscriber(Observer *subscriber, ObservableTypes... observableTypes)
Definition Notifier.h:17
Represents a state machine for BPMN execution of a scope in the model.
A class representing the state that the execution or simulation of a given scenario is in.
Definition SystemState.h:21
Represents a token running through a (sub)process.
Definition Token.h:35
const BPMN::FlowNode * node
Definition Token.h:46
const BPMNOS::Model::AttributeRegistry & getAttributeRegistry() const
Definition Token.cpp:139
const StateMachine * owner
State machine owning the token.
Definition Token.h:44
SharedValues * data
Pointer to the data of the owner or owned state machine subprocesses)
Definition Token.h:58
std::shared_ptr< DecisionRequest > decisionRequest
Definition Token.h:60
const BPMN::SequenceFlow * sequenceFlow
Definition Token.h:47
Class representing a task in which one or more choices have to be made.
Class holding extension elements representing execution data for nodes.
Abstract base class for scenarios holding data for all BPMN instances.
Definition Scenario.h:21
Class representing adhoc subprocesses with sequential ordering.
std::unique_ptr< ExtensionElements > extensionElements
Definition bpmn++.h:16299
Scope * parent
Reference to the parent node.
Definition bpmn++.h:16592
T * represents()
Attempts to cast the element to the specified type T.
Definition bpmn++.h:16236
Base class for BPMN elements that may contain a ChildNode elements.
Definition bpmn++.h:16510
void erase_ptr(std::vector< std::unique_ptr< T > > &container, const T *elementPtr)
Erase a specific element from a vector of unique pointers.
Definition erase.h:19
BPMNOS_NUMBER_TYPE number
Definition Number.h:50
Represents the event that choices are made for a DecisionTask.
Definition ChoiceEvent.h:15
std::vector< number > choices
Definition ChoiceEvent.h:18
Represents an event that increments the current time.
Class representing the event of a token having completed an activity.
Represents the event of a token entering a node.
Definition EntryEvent.h:15
std::optional< Values > entryStatus
Definition EntryEvent.h:19
Represents the event of an error being raised.
Definition ErrorEvent.h:14
Represents the event of a token exiting a node.
Definition ExitEvent.h:15
std::optional< Values > exitStatus
Definition ExitEvent.h:18
Represents the event of a message from the message pool being delivered.
Represents the event of a token ready to enter a node inclduing necressary new attribute data.
Definition ReadyEvent.h:15
BPMNOS::Values statusAttributes
Definition ReadyEvent.h:18
BPMNOS::Values dataAttributes
Definition ReadyEvent.h:19
Represents an event causing the engine to terminate.
Represents the event that a timer is triggered.
Definition TimerEvent.h:15