BPMN-OS
BPMN for optimization and simulation
Loading...
Searching...
No Matches
StochasticScenario.cpp
Go to the documentation of this file.
4#include <functional>
5
6using namespace BPMNOS::Model;
7
9 const Model* model,
10 BPMNOS::number earliestInstantiationTime,
11 BPMNOS::number latestInstantiationTime,
12 const std::unordered_map<const Attribute*, BPMNOS::number>& globalValueMap,
13 unsigned int seed
14)
15 : scenarioSeed(seed)
16 , earliestInstantiationTime(earliestInstantiationTime)
17 , latestInstantiationTime(latestInstantiationTime)
18{
19 this->model = model;
20 globals.resize(model->attributes.size());
21 for (auto& [attribute, value] : globalValueMap) {
22 globals[attribute->index] = value;
23 }
24}
25
26void StochasticScenario::addInstance(const BPMN::Process* process, const BPMNOS::number instanceId,
27 BPMNOS::number instantiationTime) {
28 instances[(size_t)instanceId] = {process, (size_t)instanceId, instantiationTime, {}};
29}
30
31void StochasticScenario::setValue(const BPMNOS::number instanceId, const Attribute* attribute,
32 std::optional<BPMNOS::number> value) {
33 instances[(size_t)instanceId].values[attribute] = value;
34}
35
37 BPMNOS::number disclosureTime) {
38 disclosure[(size_t)instanceId][node] = disclosureTime;
39}
40
43 pendingDisclosures[(size_t)instanceId].push_back(std::move(pending));
44}
45
47 const BPMN::Node* task,
48 CompletionExpression&& expr) {
49 completionExpressions[(size_t)instanceId][task].push_back(std::move(expr));
50}
51
53 const BPMN::Node* node,
54 ArrivalExpression&& expr) {
55 arrivalExpressions[(size_t)instanceId][node].push_back(std::move(expr));
56}
57
59 BPMNOS::number instanceId,
60 const BPMN::Node* node,
61 const Values& status,
62 const Values& data,
63 const Values& globals) const {
64 size_t id = (size_t)instanceId;
65
66 // Check if we have arrival expressions for this (instance, node)
67 if (!arrivalExpressions.contains(id) ||
68 !arrivalExpressions.at(id).contains(node)) {
69 return;
70 }
71
72 auto& nodeArrivalExpressions = arrivalExpressions.at(id).at(node);
73
74 // Set RNG context for random functions
75 auto& randomGenerator = getRng(id, node);
76 if (randomFactory) {
77 randomFactory->setCurrentRng(&randomGenerator);
78 }
79
80 // Evaluate arrival expressions and store values
81 for (auto& arrivalExpression : nodeArrivalExpressions) {
82 auto value = arrivalExpression.expression->execute(status, data, globals);
83 if (value.has_value() && arrivalExpression.attribute) {
84 instances.at(id).values[arrivalExpression.attribute] = value.value();
85 }
86 }
87
88 // Clear RNG context
89 if (randomFactory) {
91 }
92}
93
94std::mt19937& StochasticScenario::getRng(size_t instanceId, const BPMN::Node* node) const {
95 auto key = std::make_pair(instanceId, node);
96 if (!rngs.contains(key)) {
97 // Create RNG seeded from scenarioSeed combined with instanceId and node hash
98 size_t nodeHash = std::hash<std::string>{}(node->id);
99 size_t combinedSeed = static_cast<size_t>(scenarioSeed) ^ (instanceId * 31) ^ (nodeHash * 17);
100 rngs[key] = std::mt19937(combinedSeed);
101 }
102 return rngs[key];
103}
104
108
109bool StochasticScenario::isCompleted(const BPMNOS::number currentTime) const {
110 return currentTime > latestInstantiationTime;
111}
112
113std::vector<const Scenario::InstanceData*> StochasticScenario::getCreatedInstances(
114 const BPMNOS::number currentTime) const {
115 std::vector<const Scenario::InstanceData*> result;
116 for (auto& [id, instance] : instances) {
117 if (instance.instantiationTime <= currentTime) {
118 result.push_back(&instance);
119 }
120 }
121 return result;
122}
123
124std::vector<const Scenario::InstanceData*> StochasticScenario::getKnownInstances(
125 [[maybe_unused]] const BPMNOS::number currentTime) const {
126 std::vector<const Scenario::InstanceData*> result;
127 for (auto& [id, instance] : instances) {
128 result.push_back(&instance);
129 }
130 return result;
131}
132
133std::vector<std::tuple<const BPMN::Process*, BPMNOS::Values, BPMNOS::Values>>
135 std::vector<std::tuple<const BPMN::Process*, BPMNOS::Values, BPMNOS::Values>> result;
136 for (auto& [id, instance] : instances) {
137 BPMNOS::number effectiveInstantiationTime = instance.instantiationTime;
138 if (disclosure.contains(instance.id) && disclosure.at(instance.id).contains(instance.process)) {
139 effectiveInstantiationTime = std::max(effectiveInstantiationTime,
140 disclosure.at(instance.id).at(instance.process));
141 }
142 if (effectiveInstantiationTime == currentTime) {
143 auto status = getKnownInitialStatus(&instance, currentTime);
144 if (effectiveInstantiationTime > instance.instantiationTime) {
145 status[ExtensionElements::Index::Timestamp] = currentTime;
146 }
147 result.push_back({instance.process, std::move(status), getKnownInitialData(&instance, currentTime)});
148 }
149 }
150 return result;
151}
152
154 const BPMNOS::number currentTime) const {
155 BPMNOS::Values result;
156 for (auto& attribute : instance->process->extensionElements->as<const ExtensionElements>()->attributes) {
157 result.push_back(getKnownValue(instance, attribute.get(), currentTime));
158 }
159 return result;
160}
161
163 const BPMNOS::number currentTime) const {
164 BPMNOS::Values result;
165 for (auto& attribute : instance->process->extensionElements->as<const ExtensionElements>()->data) {
166 result.push_back(getKnownValue(instance, attribute.get(), currentTime));
167 }
168 return result;
169}
170
171std::optional<BPMNOS::number> StochasticScenario::getKnownValue(
172 const Scenario::InstanceData* instance,
173 const BPMNOS::Model::Attribute* attribute,
174 [[maybe_unused]] const BPMNOS::number currentTime) const {
175 if (attribute->expression && attribute->expression->type == Expression::Type::ASSIGN) {
176 std::vector<double> variableValues;
177 for (auto input : attribute->expression->variables) {
178 if (!input->isImmutable) {
179 return std::nullopt;
180 }
181 auto value = getKnownValue(instance, input, currentTime);
182 if (!value.has_value()) {
183 return std::nullopt;
184 }
185 variableValues.push_back((double)value.value());
186 }
187
188 std::vector<std::vector<double>> collectionValues;
189 for (auto input : attribute->expression->collections) {
190 if (!input->isImmutable) {
191 return std::nullopt;
192 }
193 collectionValues.push_back({});
194 auto collection = getKnownValue(instance, input, currentTime);
195 if (!collection.has_value()) {
196 return std::nullopt;
197 }
198 for (auto value : collectionRegistry[(size_t)collection.value()]) {
199 collectionValues.back().push_back(value);
200 }
201 }
202
203 return number(attribute->expression->compiled.evaluate(variableValues, collectionValues));
204 }
205 else {
206 if (instance->values.contains(attribute)) {
207 return instance->values.at(attribute);
208 }
209 }
210 return std::nullopt;
211}
212
213std::optional<BPMNOS::number> StochasticScenario::getKnownValue(
214 const BPMNOS::number instanceId,
215 const BPMNOS::Model::Attribute* attribute,
216 const BPMNOS::number currentTime) const {
217 return getKnownValue(&instances.at((size_t)instanceId), attribute, currentTime);
218}
219
220std::optional<BPMNOS::Values> StochasticScenario::getKnownValues(
221 const BPMNOS::number instanceId,
222 const BPMN::Node* node,
223 const BPMNOS::number currentTime) const {
224 auto& instance = instances.at((size_t)instanceId);
225 if (disclosure.contains(instance.id) && disclosure.at(instance.id).contains(node)) {
226 if (currentTime < disclosure.at(instance.id).at(node)) {
227 return std::nullopt;
228 }
229 }
230 Values result;
231 for (auto& attribute : node->extensionElements->as<const ExtensionElements>()->attributes) {
232 result.push_back(getKnownValue(&instance, attribute.get(), currentTime));
233 }
234 return result;
235}
236
237std::optional<BPMNOS::Values> StochasticScenario::getKnownData(
238 const BPMNOS::number instanceId,
239 const BPMN::Node* node,
240 const BPMNOS::number currentTime) const {
241 auto& instance = instances.at((size_t)instanceId);
242 if (disclosure.contains(instance.id) && disclosure.at(instance.id).contains(node)) {
243 if (currentTime < disclosure.at(instance.id).at(node)) {
244 return std::nullopt;
245 }
246 }
247 Values result;
248 for (auto& attribute : node->extensionElements->as<const ExtensionElements>()->data) {
249 result.push_back(getKnownValue(&instance, attribute.get(), currentTime));
250 }
251 return result;
252}
253
255 const BPMNOS::number instanceId,
256 const BPMN::Node* task,
257 BPMNOS::Values status) const {
258
259 size_t id = (size_t)instanceId;
260
261 // Check if we have completion expressions for this (instance, task)
262 if (completionExpressions.contains(id) &&
263 completionExpressions.at(id).contains(task) &&
264 !completionExpressions.at(id).at(task).empty()) {
265
266 auto& taskCompletionExpressions = completionExpressions.at(id).at(task);
267
268 // Get the task's extension elements for data
269 auto extensionElements = task->extensionElements->as<const ExtensionElements>();
270
271 // Build data values from instance
272 auto& instance = instances.at(id);
273 Values data;
274 for (auto& attribute : extensionElements->data) {
275 if (instance.values.contains(attribute.get())) {
276 data.push_back(instance.values.at(attribute.get()));
277 }
278 else {
279 data.push_back(std::nullopt);
280 }
281 }
282
283 // Set RNG context for random functions
284 auto& randomGenerator = getRng(id, task);
285 if (randomFactory) {
286 randomFactory->setCurrentRng(&randomGenerator);
287 }
288
289 // Evaluate completion expressions and update status
290 for (auto& completionExpression : taskCompletionExpressions) {
291 auto value = completionExpression.expression->execute(status, data, globals);
292 if (value.has_value() && completionExpression.attribute) {
293 // Find attribute index in status
294 size_t index = 0;
295 for (auto& attribute : extensionElements->attributes) {
296 if (attribute.get() == completionExpression.attribute) {
297 status[index] = value;
298 break;
299 }
300 ++index;
301 }
302 }
303 }
304
305 // Clear RNG context
306 if (randomFactory) {
308 }
309 }
310
311 // Store the (possibly modified) status
312 taskCompletionStatus[{id, task}] = std::move(status);
313}
314
316 for (auto& [instanceId, pendings] : pendingDisclosures) {
317 auto& instance = instances.at(instanceId);
318
319 // Process pending disclosures that are due
320 auto it = pendings.begin();
321 while (it != pendings.end()) {
322 if (currentTime >= it->disclosureTime) {
323 // Reveal pre-computed value
324 instance.values[it->attribute] = it->value;
325 disclosedAttributes.insert({instanceId, it->attribute});
326 it = pendings.erase(it);
327 }
328 else {
329 ++it;
330 }
331 }
332 }
333}
CollectionRegistry collectionRegistry
std::unique_ptr< const Expression > expression
Definition Attribute.h:31
Class holding extension elements representing execution data for nodes.
std::vector< std::unique_ptr< Attribute > > attributes
Vector containing new status attributes declared for the node.
std::vector< std::unique_ptr< Attribute > > data
Vector containing data attributes declared for data objects within the node's scope.
Represents a BPMN model with all its processes.
Definition Model.h:22
std::vector< std::unique_ptr< Attribute > > attributes
Vector containing new global attributes declared for the model.
Definition Model.h:70
std::map< std::pair< size_t, const BPMN::Node * >, BPMNOS::Values > taskCompletionStatus
Stored completion status per (instanceId, task)
Definition Scenario.h:147
const Model * model
Pointer to the BPMN model.
Definition Scenario.h:148
BPMNOS::Values globals
Definition Scenario.h:144
std::unordered_map< size_t, std::vector< StochasticPendingDisclosure > > pendingDisclosures
Instance ID -> pending disclosures.
std::unordered_map< size_t, std::unordered_map< const BPMN::Node *, std::vector< ArrivalExpression > > > arrivalExpressions
Arrival expressions per (instance, node)
void revealData(BPMNOS::number currentTime) const
void setValue(const BPMNOS::number instanceId, const Attribute *attribute, std::optional< BPMNOS::number > value)
void addArrivalExpression(const BPMNOS::number instanceId, const BPMN::Node *node, ArrivalExpression &&expr)
void addInstance(const BPMN::Process *process, const BPMNOS::number instanceId, BPMNOS::number instantiationTime)
Values getKnownInitialData(const InstanceData *, const BPMNOS::number time) const override
Method returning the initial data attributes for process instantiation.
BPMNOS::number getEarliestInstantiationTime() const override
Method returning the time of the earliest instantiation.
std::vector< const InstanceData * > getCreatedInstances(const BPMNOS::number currentTime) const override
Method returning a vector of all instances that have been created until the given time.
std::unordered_map< size_t, InstanceData > instances
void addPendingDisclosure(const BPMNOS::number instanceId, StochasticPendingDisclosure &&pending)
std::vector< const InstanceData * > getKnownInstances(const BPMNOS::number currentTime) const override
Method returning a vector of all instances that have been created or are known for sure until the giv...
void setTaskCompletionStatus(const BPMNOS::number instanceId, const BPMN::Node *task, BPMNOS::Values status) const override
Store the completion status when a task enters BUSY state.
std::vector< std::tuple< const BPMN::Process *, BPMNOS::Values, BPMNOS::Values > > getCurrentInstantiations(const BPMNOS::number currentTime) const override
Method returning a vector of all instances that are known to be instantiated at the given time.
void setDisclosure(const BPMNOS::number instanceId, const BPMN::Node *node, BPMNOS::number disclosureTime)
std::set< std::pair< size_t, const Attribute * > > disclosedAttributes
Track which attributes have been disclosed.
std::optional< BPMNOS::Values > getKnownData(const BPMNOS::number instanceId, const BPMN::Node *node, const BPMNOS::number currentTime) const override
Method returning all known values of new attributes.
std::map< std::pair< size_t, const BPMN::Node * >, std::mt19937 > rngs
Per (instance, node) RNG for reproducibility.
Values getKnownInitialStatus(const InstanceData *, const BPMNOS::number time) const override
Method returning the initial status attributes for process instantiation.
bool isCompleted(const BPMNOS::number currentTime) const override
Method returning true if the currentTime exceeds the completion time.
RandomDistributionFactory * randomFactory
RandomDistributionFactory for expression evaluation (set by provider)
std::optional< BPMNOS::number > getKnownValue(const Scenario::InstanceData *instance, const BPMNOS::Model::Attribute *attribute, const BPMNOS::number currentTime) const override
Method returning a known value of an attribute.
std::optional< BPMNOS::Values > getKnownValues(const BPMNOS::number instanceId, const BPMN::Node *node, const BPMNOS::number currentTime) const override
Method returning all known values of new attributes.
std::mt19937 & getRng(size_t instanceId, const BPMN::Node *node) const
Get or create RNG for (instance, node) pair.
void initializeArrivalData(BPMNOS::number instanceId, const BPMN::Node *node, const Values &status, const Values &data, const Values &globals) const override
Initialize arrival data when a token arrives at an activity.
void addCompletionExpression(const BPMNOS::number instanceId, const BPMN::Node *task, CompletionExpression &&expr)
StochasticScenario(const Model *model, BPMNOS::number earliestInstantiationTime, BPMNOS::number latestInstantiationTime, const std::unordered_map< const Attribute *, BPMNOS::number > &globalValueMap, unsigned int seed=0)
std::unordered_map< size_t, std::unordered_map< const BPMN::Node *, BPMNOS::number > > disclosure
Instance ID -> Node -> disclosure time.
std::unordered_map< size_t, std::unordered_map< const BPMN::Node *, std::vector< CompletionExpression > > > completionExpressions
Completion expressions per (instance, node)
void setCurrentRng(std::mt19937 *rng)
Set the current RNG to use for expression evaluation.
std::unique_ptr< ExtensionElements > extensionElements
Definition bpmn++.h:16299
std::string id
Id of element.
Definition bpmn++.h:16298
Base class for all nodes in a BPMN model.
Definition bpmn++.h:16444
BPMNOS_NUMBER_TYPE number
Definition Number.h:50
Structure representing an arrival expression.
Structure representing a completion expression.
std::unordered_map< const Attribute *, std::optional< BPMNOS::number > > values
Attribute values.
Definition Scenario.h:27
const BPMN::Process * process
Definition Scenario.h:24
Structure representing a pending disclosure.