14 , instanceId(instanceId)
19 if (
parent.has_value() ) {
20 dataOwners = parent.value().first.dataOwners;
47 const Vertex* entry = (type == Type::ENTRY ? this :
this - 1);
48 const Vertex* exit = (type == Type::EXIT ? this :
this + 1);
50 assert( entry->
parent.has_value() );
51 auto parentVertices = entry->
parent.value();
52 entry = &parentVertices.first;
53 exit = &parentVertices.second;
54 }
while ( entry->
node != performer );
56 return { *entry, *exit };
61 const Vertex* entry = (type == Type::ENTRY ? this :
this - 1);
62 const Vertex* exit = (type == Type::EXIT ? this :
this + 1);
65 assert( entry->
parent.has_value() );
66 auto parentVertices = entry->
parent.value();
67 entry = &parentVertices.first;
68 exit = &parentVertices.second;
72 return { *entry, *exit };
76 return BPMNOS::to_string(instanceId,
STRING) +
"," + node->id +
"," + ( type == Type::ENTRY ?
"entry" :
"exit" );
83 for (
auto& instance : instances ) {
90 auto [ entry, exit ] = createVertexPair(instance->
id, instance->
id, instance->
process, std::nullopt);
92 flatten( instance->
id, instance->
process, entry, exit );
95void FlattenedGraph::addNonInterruptingEventSubProcess(
const BPMN::EventSubProcess* eventSubProcess, Vertex& parentEntry, Vertex& parentExit ) {
96 nonInterruptingEventSubProcesses.emplace_back(eventSubProcess, parentEntry, parentExit, 0,
nullptr);
98 auto& counter = std::get<unsigned int>( nonInterruptingEventSubProcesses.back() );
99 auto& lastStart = std::get<Vertex*>( nonInterruptingEventSubProcesses.back() );
104 for (
auto candidate : candidates ) {
105 for ( [[maybe_unused]]
auto& _ : sendingVertices[candidate] ) {
109 flatten(
id, eventSubProcess, parentEntry, parentExit );
112 assert( container.size() >= 2 );
113 Vertex& startExit = container[container.size()-1];
115 Vertex& startEntry = container[container.size()-2];
116 lastStart->successors.push_back(startEntry);
117 startEntry.predecessors.push_back(*lastStart);
119 lastStart = &startExit;
124void FlattenedGraph::addSender(
const BPMN::MessageThrowEvent* messageThrowEvent, Vertex& senderEntry, Vertex& senderExit ) {
129 for (
auto& [eventSubProcess, parentEntry, parentExit, counter, lastStart] : nonInterruptingEventSubProcesses ) {
130 if (std::find(candidates.begin(), candidates.end(), eventSubProcess->
startEvent) != candidates.end()) {
134 flatten(
id, eventSubProcess, parentEntry, parentExit );
139 for (
auto candidate : candidates ) {
140 for (
auto& [ recipientEntry, recipientExit] : receivingVertices[candidate] ) {
141 senderEntry.recipients.push_back(recipientExit);
142 recipientExit.senders.push_back(senderEntry);
144 recipientExit.recipients.push_back(senderExit);
145 senderExit.senders.push_back(recipientExit);
150 sendingVertices[messageThrowEvent].emplace_back(senderEntry, senderExit);
153void FlattenedGraph::addRecipient(
const BPMN::MessageCatchEvent* messageCatchEvent, Vertex& recipientEntry, Vertex& recipientExit ) {
158 for (
auto candidate : candidates ) {
159 for (
auto& [ senderEntry, senderExit] : sendingVertices[candidate] ) {
160 senderEntry.recipients.push_back(recipientExit);
161 recipientExit.senders.push_back(senderEntry);
163 recipientExit.recipients.push_back(senderExit);
164 senderExit.senders.push_back(recipientExit);
169 receivingVertices[messageCatchEvent].emplace_back(recipientEntry, recipientExit);
172std::pair<FlattenedGraph::Vertex&, FlattenedGraph::Vertex&> FlattenedGraph::createVertexPair(
BPMNOS::number rootId,
BPMNOS::number instanceId,
const BPMN::Node* node, std::optional< std::pair<Vertex&, Vertex&> > parent) {
178 entry.successors.push_back(exit);
179 exit.predecessors.push_back(entry);
181 if ( parent.has_value() ) {
182 entry.predecessors.push_back( parent.value().first );
183 exit.successors.push_back( parent.value().second );
184 parent.value().first.successors.push_back( entry );
185 parent.value().second.predecessors.push_back( exit );
188 auto& container =
vertexMap[node][instanceId];
189 container.emplace_back( entry );
190 container.emplace_back( exit );
195 if ( !extensionElements ) {
196 return { entry, exit };
200 addSender( messageThrowEvent, entry, exit );
203 addRecipient( messageCatchEvent, entry, exit );
206 if ( extensionElements->data.size() ) {
207 entry.dataOwners.push_back( entry );
208 exit.dataOwners.push_back( entry );
212 if ( extensionElements->hasSequentialPerformer ) {
216 sequentialAdHocSubProcess && !sequentialAdHocSubProcess->
performer
222 auto performerVertices = entry.performer();
227 if ( extensionElements->data.size() ) {
228 dataModifiers.emplace(&entry,std::vector< std::pair<const Vertex&, const Vertex&> >());
233 for (
auto& operator_ : extensionElements->operators ) {
235 auto dataOwnerVertices = entry.dataOwner(operator_->attribute);
236 dataModifiers.at( &dataOwnerVertices.first ).push_back( { entry, exit } );
244 return { entry, exit };
275 assert(extensionElements);
278 if ( extensionElements->loopMaximum.has_value() ) {
279 auto value = getValue( extensionElements->loopMaximum.value().get(),
INTEGER );
280 n = value.has_value() ? (int)value.value() : 0;
284 if ( extensionElements->loopMaximum.has_value() ) {
285 auto value = getValue( extensionElements->loopCardinality.value().get(),
INTEGER );
286 n = value.has_value() ? (int)value.value() : 0;
310 throw std::runtime_error(
"FlattenedGraph: cannot determine loop maximum/cardinality for activity '" + activity->
id +
"'" );
315 for (
int i = 1; i <= n; i++ ) {
316 createVertexPair(rootId, instanceId, activity, parent);
322 for (
int i = 1; i <= n; i++ ) {
329 auto& container =
vertexMap.at(activity).at(instanceId);
330 for (
size_t i = 1; i < container.size(); i += 2 ) {
331 Vertex& predecessor = container[i];
332 Vertex& successor = container[i+1];
333 predecessor.successors.push_back(successor);
334 successor.predecessors.push_back(predecessor);
340void FlattenedGraph::flatten(
BPMNOS::number instanceId,
const BPMN::Scope* scope, Vertex& scopeEntry, Vertex& scopeExit) {
341 std::pair<Vertex&, Vertex&> parent = {scopeEntry,scopeExit};
342 for (
auto& flowNode : scope->
flowNodes ) {
347 createLoopVertices(scopeEntry.rootId, instanceId, activity, parent);
350 createVertexPair(scopeEntry.rootId, instanceId, flowNode, parent);
353 auto& container =
vertexMap.at(flowNode).at(instanceId);
362 if (
auto childScope = flowNode->represents<
BPMN::Scope>() ) {
363 assert( container.size() % 2 == 0 );
364 for (
size_t i = 0; i < container.size(); i += 2 ) {
365 Vertex& entry = container[i];
366 Vertex& exit = container[i+1];
367 flatten( entry.instanceId, childScope, entry, exit );
374 Vertex& origin =
vertexMap.at(sequenceFlow->source).at(instanceId).front();
375 Vertex& destination =
vertexMap.at(sequenceFlow->target).at(instanceId).back();
376 origin.outflows.emplace_back(sequenceFlow.get(),destination);
377 destination.inflows.emplace_back(sequenceFlow.get(),origin);
381 for (
auto& flowNode : scope->
flowNodes ) {
383 throw std::runtime_error(
"FlattenedGraph: Boundary event '" + boundaryEvent->id +
"' is not yet supported");
391 flatten( instanceId, eventSubProcess, scopeEntry, scopeExit );
396 addNonInterruptingEventSubProcess(eventSubProcess, scopeEntry, scopeExit);
399 throw std::runtime_error(
"FlattenedGraph: Type of non-interrupting event-subprocess '" + eventSubProcess->
id +
"' is not supported");
405 for (
auto& flowNode : scope->
flowNodes ) {
408 throw std::runtime_error(
"FlattenedGraph: Compensation activity '" + activity->
id +
"' is not yet supported");
std::pair< const Vertex &, const Vertex & > performer() const
Container holding all entry vertices of nodes owning at least one data attribute.
std::optional< std::pair< Vertex &, Vertex & > > parent
std::pair< const Vertex &, const Vertex & > dataOwner(const BPMNOS::Model::Attribute *attribute) const
Returns the vertices of the performer of a sequential activity vertex.
std::string reference() const
Returns the vertices of the owner of a data attribute.
void addInstance(const BPMNOS::Model::Scenario::InstanceData *instance)
Map holding entry and exit vertices of each possible instantiation of a node.
std::unordered_map< const Vertex *, std::vector< std::pair< const Vertex &, const Vertex & > > > dataModifiers
Container allowing to look up vertices of sequential activities given a pointer to the entry vertex o...
std::deque< Vertex > vertices
Container holding entry vertices of all process instances.
std::unordered_map< const Vertex *, std::vector< std::pair< const Vertex &, const Vertex & > > > sequentialActivities
const BPMNOS::Model::Scenario * scenario
std::vector< std::reference_wrapper< Vertex > > initialVertices
std::unordered_map< const BPMN::Node *, std::unordered_map< BPMNOS::number, std::vector< std::reference_wrapper< Vertex > > > > vertexMap
Container holding entry and exit vertices of each possible instantiation of a node.
std::vector< std::pair< const Vertex &, const Vertex & > > globalModifiers
Container allowing to look up vertices of tasks modifying data attributes given a pointer to the entr...
FlattenedGraph(const BPMNOS::Model::Scenario *scenario)
std::map< std::string, Attribute * > dataAttributes
size_t index
Index of attribute (is automatically set by attribute registry).
Class holding extension elements representing execution data for nodes.
AttributeRegistry attributeRegistry
Registry allowing to look up all status and data attributes by their names.
std::vector< std::unique_ptr< Attribute > > data
Vector containing data attributes declared for data objects within the node's scope.
The Scenario class holds data for all BPMN instances.
static constexpr char delimiters[]
Delimiters used for disambiguation of identifiers of non-interrupting event subprocesses and multi-in...
std::vector< const InstanceData * > getKnownInstances(const BPMNOS::number currentTime) const
Method returning a vector of all instances that have been created or are known for sure until the giv...
Class representing adhoc subprocesses with sequential ordering.
std::optional< LoopCharacteristics > loopCharacteristics
std::unique_ptr< ExtensionElements > extensionElements
std::string id
Id of element.
Base class for all boundary events attached to an Activity.
Scope * parent
Reference to the parent node.
T * as()
Casts the element to the specified type T.
T * represents()
Attempts to cast the element to the specified type T.
TypedStartEvent * startEvent
Base class for all nodes in a BPMN model.
Base class for BPMN elements that may contain a ChildNode elements.
std::vector< EventSubProcess * > eventSubProcesses
Vector containing pointers to all event subprocesses within the scope of the nodes.
std::vector< FlowNode * > flowNodes
Vector containing pointers to all flow nodes within the scope of the nodes.
std::vector< std::unique_ptr< SequenceFlow > > sequenceFlows
Vector containing all sequence flows within the scope.
std::string to_string(number numericValue, const ValueType &type)
Converts a number to a string.
number to_number(const std::string &valueString, const ValueType &type)
Converts a string to a number.
BPMNOS_NUMBER_TYPE number
const BPMN::Process * process
size_t id
Instance identifier.