BPMN-OS
BPMN for optimization and simulation
Loading...
Searching...
No Matches
StaticDataProvider.cpp
Go to the documentation of this file.
7#include <unordered_map>
8#include <algorithm>
9#include <ranges>
10
11using namespace BPMNOS::Model;
12
13StaticDataProvider::StaticDataProvider(const std::string& modelFile, const std::string& instanceFileOrString)
14 : StaticDataProvider(modelFile,{},instanceFileOrString)
15{
16}
17
18StaticDataProvider::StaticDataProvider(const std::string& modelFile, const std::vector<std::string>& folders, const std::string& instanceFileOrString)
19 : DataProvider(modelFile,folders)
20 , reader( CSVReader(instanceFileOrString) )
21{
22 for ( auto& [ attributeId, attribute ] : attributes[nullptr] ) {
23 if ( attribute->expression ) {
24 if ( attribute->expression->compiled.getVariables().size() || attribute->expression->compiled.getCollections().size() ) {
25 throw std::runtime_error("StaticDataProvider: initial value of global attribute '" + attribute->id + "' must not be derived from other attributes");
26 }
27 globalValueMap[ attribute ] = attribute->expression->compiled.evaluate();
28 }
29 }
30 earliestInstantiation = std::numeric_limits<BPMNOS::number>::max();
31 latestInstantiation = std::numeric_limits<BPMNOS::number>::min();
33
34}
35
37 enum {PROCESS_ID, INSTANCE_ID, ATTRIBUTE_ID, VALUE};
38
40 if ( table.empty() ) {
41 throw std::runtime_error("StaticDataProvider: table '" + reader.instanceFileOrString + "' is empty");
42 }
43
44 for (auto &row : table | std::views::drop(1)) { // assume a single header line
45 if ( row.empty() ) {
46 continue;
47 }
48 if ( row.size() != 4 ) {
49 throw std::runtime_error("StaticDataProvider: illegal number of cells");
50 }
51 if ( !std::holds_alternative<std::string>(row.at(PROCESS_ID)) ) {
52 throw std::runtime_error("StaticDataProvider: illegal process id");
53 }
54 std::string processId = std::get<std::string>(row.at(PROCESS_ID));
55
56 if ( processId.size() ) {
57 // find process with respective identifier
58 auto processIt = std::find_if(
59 model->processes.begin(),
60 model->processes.end(),
61 [&processId](const std::unique_ptr<BPMN::Process>& process) { return process->id == processId;}
62 );
63 if ( processIt == model->processes.end() ) {
64 throw std::runtime_error("StaticDataProvider: model has no process '" + processId + "'");
65 }
66
67 auto process = processIt->get();
68
69 if ( !std::holds_alternative<std::string>(row.at(INSTANCE_ID)) ) {
70 throw std::runtime_error("StaticDataProvider: illegal instance id");
71 }
72 auto instanceId = (size_t)BPMNOS::to_number(std::get<std::string>(row.at(INSTANCE_ID)), STRING );
73// auto instanceId = (long unsigned int)BPMNOS::to_number( row[INSTANCE_ID].get(), STRING );
74 // find instance with respective identifier
75 if ( !instances.contains(instanceId) ) {
76 // row has first entry for instance, create new entry in data
77 instances[instanceId] = StaticInstanceData({process,instanceId,std::numeric_limits<BPMNOS::number>::max(),{}});
78 }
79
80 auto& instance = instances[instanceId];
81
82 if ( !std::holds_alternative<std::string>(row.at(ATTRIBUTE_ID)) ) {
83 throw std::runtime_error("StaticDataProvider: illegal attribute id");
84 }
85 std::string attributeId = std::get<std::string>(row.at(ATTRIBUTE_ID));
86// std::string attributeId = row[ATTRIBUTE_ID].get();
87
88 if ( attributeId == "" ) {
89 // no attribute provided in this row
90 continue;
91 }
92
93 if ( !attributes[process].contains(attributeId) ) {
94 throw std::runtime_error("StaticDataProvider: process '" + processId + "' has no node with attribute '" + attributeId + "'");
95 }
96
97 auto attribute = attributes[process][attributeId];
98 if ( attribute->expression ) {
99 throw std::runtime_error("StaticDataProvider: value of attribute '" + attributeId + "' is initialized by expression and must not be provided explicitly");
100 }
101
102 if ( !std::holds_alternative<BPMNOS::number>(row.at(VALUE)) ) {
103 throw std::runtime_error("StaticDataProvider: illegal value");
104 }
105 instance.data[ attribute ] = std::get<BPMNOS::number>(row.at(VALUE)); //BPMNOS::to_number(row[VALUE].get(),attribute->type);
106//std::cerr << processId << ", " << BPMNOS::to_string(instanceId,STRING) << ", " << attributeId << ", " << BPMNOS::to_string(instance.data[ attribute ],attribute->type) << std::endl;
107 }
108 else {
109 // row contains global attribute
110 if ( !std::holds_alternative<std::string>(row.at(ATTRIBUTE_ID)) ) {
111 throw std::runtime_error("StaticDataProvider: illegal attribute id");
112 }
113 std::string attributeId = std::get<std::string>(row.at(ATTRIBUTE_ID));
114// std::string attributeId = row[ATTRIBUTE_ID].get();
115 auto attribute = attributes[nullptr][attributeId];
116 if ( !std::holds_alternative<BPMNOS::number>(row.at(VALUE)) ) {
117 throw std::runtime_error("StaticDataProvider: illegal value");
118 }
119 globalValueMap[attribute] = std::get<BPMNOS::number>(row.at(VALUE)); //BPMNOS::to_number(row[VALUE].get(),attribute->type);
120//std::cerr << ", " << ", " << attributeId << ", " << BPMNOS::to_string(globalValueMap[attribute],attribute->type) << std::endl;
121 }
122 }
123
124 for (auto& [id, instance] : instances) {
125 // ensure that default attributes are available
128 // set time of instantiation
129 instance.instantiation = instance.data.at( attributes[instance.process][Keyword::Timestamp] );
130
131 if ( earliestInstantiation > instance.instantiation ) {
132 earliestInstantiation = instance.instantiation;
133 }
134 if ( latestInstantiation < instance.instantiation ) {
135 latestInstantiation = instance.instantiation;
136 }
137 }
138}
139
140void StaticDataProvider::ensureDefaultValue(StaticInstanceData& instance, const std::string attributeId, std::optional<BPMNOS::number> value) {
141 assert( attributes.contains(instance.process) );
142 auto it1 = attributes.at(instance.process).find(attributeId);
143 if ( it1 == attributes.at(instance.process).end() ) {
144 throw std::runtime_error("StaticDataProvider: unable to find required attribute '" + attributeId + "' for process '" + instance.process->id + "'");
145 }
146 auto attribute = it1->second;
147 if ( auto it2 = instance.data.find( attribute );
148 it2 == instance.data.end()
149 ) {
150 if ( attribute->expression ) {
151 throw std::runtime_error("StaticDataProvider: initial value of default attribute '" + attribute->id + "' must not be provided by expression");
152 }
153
154 // set attribute value if available
155 if ( value.has_value() ) {
156 instance.data[ attribute ] = value.value();
157 }
158 else if ( attributeId == BPMNOS::Keyword::Timestamp ) {
159 // use 0 as fallback
160 instance.data[ attribute ] = 0;
161 }
162 else {
163 throw std::runtime_error("StaticDataProvider: attribute '" + attribute->id + "' has no default value");
164 }
165 }
166}
167
168std::unique_ptr<Scenario> StaticDataProvider::createScenario(unsigned int scenarioId) {
169 std::unique_ptr<Scenario> scenario = std::make_unique<Scenario>(model.get(), earliestInstantiation, latestInstantiation, attributes, globalValueMap, scenarioId);
170 for ( auto& [id, instance] : instances ) {
171 auto& timestampAttribute = attributes[instance.process][Keyword::Timestamp];
172 auto& instantiation = instance.data[timestampAttribute];
173 scenario->addInstance(instance.process, id, { {}, {{earliestInstantiation, instantiation}} }); // all instances are known at time of the earliest instantiation, but instantiations may occur later
174 for ( auto& [attribute, value] : instance.data ) {
175 scenario->setRealization( scenario->getAttributeData(id, attribute), {earliestInstantiation, value} ); // all attribute values are known at time of the earliest instantiation
176 }
177 }
178 return scenario;
179}
std::vector< Row > Table
Definition CSVReader.h:17
const std::string instanceFileOrString
Definition CSVReader.h:21
Abstract base class representing a data provider for BPMN instance data.
DataInput attributes
Map holding all attributes in the model with keys being the process (or nullptr for global attributes...
std::unique_ptr< Model > model
Pointer to the BPMN model.
Class representing a data provider for static BPMN instance data.
std::unordered_map< const Attribute *, BPMNOS::number > globalValueMap
std::unique_ptr< Scenario > createScenario(unsigned int scenarioId=0) override
StaticDataProvider(const std::string &modelFile, const std::string &instanceFileOrString)
Constructor for StaticDataProvider.
std::unordered_map< long unsigned int, StaticInstanceData > instances
void ensureDefaultValue(StaticInstanceData &instance, const std::string attributeId, std::optional< BPMNOS::number > value=std::nullopt)
std::string id
Id of element.
Definition bpmn++.h:16298
const std::string Instance
Definition Keywords.h:13
const std::string Timestamp
Definition Keywords.h:12
number to_number(const std::string &valueString, const ValueType &type)
Converts a string to a number.
Definition Number.cpp:57
@ STRING
Definition Value.h:9
std::unordered_map< const Attribute *, BPMNOS::number > data