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
16{
17 clockTick = 1;
18}
19
21{
22//std::cerr << "~Engine()" << std::endl;
23}
24
26 if ( token_ptr.has_value() && token_ptr->expired() ) {
27 // relevant token no longer exists, skip command
28 return;
29 }
30
31 if ( stateMachine_ptr.has_value() && stateMachine_ptr->expired() ) {
32 // relevant state machine no longer exists, skip command
33 return;
34 }
35
36 function();
37}
38
40 // create initial system state
41 systemState = std::make_unique<SystemState>(this, scenario);
42 conditionalEventObserver = std::make_unique<ConditionalEventObserver>(systemState.get());
44
45 // advance all tokens in system state
46 while ( advance() ) {
47//std::cerr << ".";
48 if ( !systemState->isAlive() ) {
49//std::cerr << "dead" << std::endl;
50 break;
51 }
52 if ( systemState->getTime() > timeout ) {
53//std::cerr << "timeout" << std::endl;
54 break;
55 }
56 }
57
58 // get final objective value
59 return systemState->getObjective();
60// std::cout << "Objective (maximization): " << (float)objective << std::endl;
61// std::cout << "Objective (minimization): " << -(float)objective << std::endl;
62}
63
65 // make sure new data is added to system state
66 const_cast<BPMNOS::Model::Scenario*>(systemState->scenario)->update();
67
68 // add all new instances and advance tokens
70 // it is assumed that at least one clock tick or termination event is processed to ensure that
71 // each instance is only added once
72
73 while ( commands.size() ) {
74//std::cerr << "execute" << std::endl;
75 auto command = std::move(commands.front());
76 commands.pop_front();
77 command.execute();
78 }
79
80 // fetch and process all events
81 while ( auto event = fetchEvent(systemState.get()) ) {
82//std::cerr << "*";
83 notify(event.get());
84 event->processBy(this);
85
86 while ( commands.size() ) {
87 commands.front().execute();
88 commands.pop_front();
89 }
90
91 if ( event->is<ClockTickEvent>() ) {
92//std::cerr << "ClockTick" << std::endl;
93 // exit loop to resume
94 return true;
95 }
96
97 if ( event->is<TerminationEvent>() ) {
98 // exit loop to terminate
99 return false;
100 }
101 }
102
103 throw std::runtime_error("Engine: unexpected absence of event");
104}
105
107 for (auto& [process,status,data] : systemState->getInstantiations() ) {
108 if ( !process->isExecutable ) {
109 throw std::runtime_error("Engine: process '" + process->id + "' is not executable");
110 }
111 if ( !data[Model::ExtensionElements::Index::Instance].has_value() ) {
112 throw std::runtime_error("Engine: instance of process '" + process->id + "' has no id");
113 }
114 if ( !status[Model::ExtensionElements::Index::Timestamp].has_value() ) {
115 throw std::runtime_error("Engine: instance of process '" + process->id + "' has no timestamp");
116 }
117 systemState->instantiationCounter++;
118 systemState->instances.push_back(std::make_shared<StateMachine>(systemState.get(),process,std::move(data)));
119 // run instance and advance token
120 systemState->instances.back()->run(std::move(status));
121 }
122}
123
125//std::cerr << "deleteInstance" << std::endl;
126 erase_ptr<StateMachine>(systemState->instances,instance);
127}
128
129void Engine::process(const ReadyEvent* event) {
130//std::cerr << "ReadyEvent " << event.token->node->id << std::endl;
131 Token* token = const_cast<Token*>(event->token);
133 systemState->tokensAwaitingReadyEvent.remove(token);
134
135 token->sequenceFlow = nullptr;
136 token->status.insert(token->status.end(), event->statusAttributes.begin(), event->statusAttributes.end());
137
138 if ( auto scope = token->node->represents<BPMN::Scope>() ) {
139 const_cast<StateMachine*>(token->owner)->createChild(token, scope, event->dataAttributes);
140 }
141 commands.emplace_back(std::bind(&Token::advanceToReady,token), token);
142}
143
144void Engine::process(const EntryEvent* event) {
145//std::cerr << systemState->pendingEntryEvents.empty() << "EntryEvent " << event->token->jsonify().dump() << std::endl;
146 Token* token = const_cast<Token*>(event->token);
147 token->decisionRequest.reset();
150 token->occupySequentialPerformer();
151 }
152
153 // update token status
154 if ( event->entryStatus.has_value() ) {
155 token->status = event->entryStatus.value();
156 }
157
158 commands.emplace_back(std::bind(&Token::advanceToEntered,token), token);
159}
160
161void Engine::process(const ChoiceEvent* event) {
162//std::cerr << "ChoiceEvent " << event.token->node->id << std::endl;
163 Token* token = const_cast<Token*>(event->token);
164 token->decisionRequest.reset();
166 assert( token->node );
167 assert( token->node->represents<BPMNOS::Model::DecisionTask>() );
168
169 auto extensionElements = token->node->extensionElements->as<BPMNOS::Model::ExtensionElements>();
170 assert( extensionElements );
171 assert( extensionElements->choices.size() == event->choices.size() );
172 // apply choices
173 for (size_t i = 0; i < extensionElements->choices.size(); i++) {
174 extensionElements->attributeRegistry.setValue( extensionElements->choices[i]->attribute, token->status, *token->data, token->globals, event->choices[i] );
175 }
176
177 commands.emplace_back(std::bind(&Token::advanceToCompleted,token), token);
178}
179
181//std::cerr << "CompletionEvent " << event.token->node->id << std::endl;
182 Token* token = const_cast<Token*>(event->token);
184 systemState->tokensAwaitingCompletionEvent.remove(token);
185 // update token status
186 if ( event->updatedStatus.has_value() ) {
187 token->status = std::move( event->updatedStatus.value() );
188 }
189
190 commands.emplace_back(std::bind(&Token::advanceToCompleted,token), token);
191}
192
194 Token* token = const_cast<Token*>(event->token);
195 token->decisionRequest.reset();
197 assert( token->node );
198
199 auto message_ptr = event->message.lock();
200 assert( message_ptr );
201 Message* message = const_cast<Message*>(message_ptr.get());
202 // update token status
203 message->apply(token->node,token->getAttributeRegistry(),token->status,*token->data,token->globals);
204
206 notify(message);
207
208 erase_ptr<Message>(systemState->messages,message);
209
210 if ( message->waitingToken ) {
211 // send task is completed
212 systemState->messageAwaitingDelivery.erase( message->waitingToken );
213 commands.emplace_back(std::bind(&Token::advanceToCompleted,message->waitingToken), message->waitingToken);
214 }
215
216 commands.emplace_back(std::bind(&Token::advanceToCompleted,token), token);
217}
218
219void Engine::process(const ExitEvent* event) {
220//std::cerr << "ExitEvent: " << event->token->jsonify().dump() << std::endl;
221 Token* token = const_cast<Token*>(event->token);
222 token->decisionRequest.reset();
223
225 token->releaseSequentialPerformer();
226 }
227
228 // update token status
229 if ( event->exitStatus.has_value() ) {
230 token->status = event->exitStatus.value();
231 }
232
233 commands.emplace_back(std::bind(&Token::advanceToExiting,token), token);
234}
235
236void Engine::process(const ErrorEvent* event) {
237 Token* token = const_cast<Token*>(event->token);
238 commands.emplace_back(std::bind(&Token::advanceToFailed,token), token);
239}
240
241void Engine::process([[maybe_unused]] const ClockTickEvent* event) {
242//std::cerr << "ClockTickEvent " << std::endl;
243 systemState->incrementTimeBy(clockTick);
244 // trigger tokens awaiting timer
245 while ( !systemState->tokensAwaitingTimer.empty() ) {
246 auto it = systemState->tokensAwaitingTimer.begin();
247 auto [time, token_ptr] = *it;
248 if ( time > systemState->getTime() ) {
249 break;
250 }
251 auto token = token_ptr.lock();
252 assert( token );
253 notify(TimerEvent(token.get()));
254 commands.emplace_back(std::bind(&Token::advanceToCompleted,token.get()), token.get());
255 systemState->tokensAwaitingTimer.remove(token.get());
256 }
257}
258
259void Engine::process([[maybe_unused]] const TerminationEvent* event) {
260 throw std::runtime_error("Engine: TerminationEvent not yet implemented");
261}
262
263
265 return systemState->currentTime;
266}
267
269 return systemState.get();
270}
271
void process(const ReadyEvent *event)
Definition Engine.cpp:129
void deleteInstance(StateMachine *instance)
Method removing completed instance.
Definition Engine.cpp:124
BPMNOS::number clockTick
Timestep used to advance the current time by systemState.time += clockTick.
Definition Engine.h:97
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:39
std::unique_ptr< ConditionalEventObserver > conditionalEventObserver
Definition Engine.h:99
std::unique_ptr< SystemState > systemState
Definition Engine.h:98
std::list< Command > commands
List of commands to be executed.
Definition Engine.h:91
const SystemState * getSystemState()
Returns a pointer to the system state.
Definition Engine.cpp:268
BPMNOS::number getCurrentTime()
Returns the timestamp the engine is in.
Definition Engine.cpp:264
void addInstances()
Method adding all new instances and advancing tokens as much as possible.
Definition Engine.cpp:106
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:16
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.
The Scenario class holds data for all BPMN instances.
Definition Scenario.h:20
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:16568
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:42
Represents the event that choices are made for a DecisionTask.
Definition ChoiceEvent.h:15
Represents an event that increments the current time.
Class representing the event of a token having completed an activity.
std::optional< Values > updatedStatus
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