22 , reader(
CSVReader(instanceFileOrString) )
24 for (
auto& [ attributeId, attribute ] :
attributes[
nullptr] ) {
25 if ( attribute->expression ) {
29 globals[attr->index] = value;
31 auto value = attribute->expression->execute(
Values{},
Values{}, globals);
32 if ( !value.has_value() ) {
33 throw std::runtime_error(
"DynamicDataProvider: failed to evaluate global attribute '" + attribute->id +
"'");
46 if ( table.empty() ) {
50 if ( table.size() < 2 ) {
51 throw std::runtime_error(
"DynamicDataProvider: table must have at least a header and one data row");
54 size_t columnCount = table[0].size();
55 if ( columnCount != 4 ) {
56 throw std::runtime_error(
"DynamicDataProvider: expected 4 columns (INSTANCE_ID, NODE_ID, INITIALIZATION, DISCLOSURE), got " + std::to_string(columnCount));
60 enum {INSTANCE_ID, NODE_ID, INITIALIZATION, DISCLOSURE};
62 for (
auto &row : table | std::views::drop(1)) {
66 if ( row.size() != 4 ) {
67 throw std::runtime_error(
"DynamicDataProvider: illegal number of cells");
71 if ( !std::holds_alternative<std::string>(row.at(INSTANCE_ID)) ) {
72 throw std::runtime_error(
"DynamicDataProvider: illegal instance id");
74 std::string instanceIdStr = std::get<std::string>(row.at(INSTANCE_ID));
77 if ( !std::holds_alternative<std::string>(row.at(NODE_ID)) ) {
78 throw std::runtime_error(
"DynamicDataProvider: illegal node id");
80 std::string nodeId = std::get<std::string>(row.at(NODE_ID));
83 if ( !std::holds_alternative<std::string>(row.at(INITIALIZATION)) ) {
84 throw std::runtime_error(
"DynamicDataProvider: illegal initialization");
86 std::string initialization = std::get<std::string>(row.at(INITIALIZATION));
89 if ( !std::holds_alternative<std::string>(row.at(DISCLOSURE)) ) {
90 throw std::runtime_error(
"DynamicDataProvider: illegal disclosure");
92 std::string disclosureStr = std::get<std::string>(row.at(DISCLOSURE));
94 if ( instanceIdStr.empty() && nodeId.empty() ) {
96 if ( !disclosureStr.empty() ) {
97 throw std::runtime_error(
"DynamicDataProvider: global attributes must not have disclosure expression");
99 if ( initialization.empty() ) {
105 for (
auto& [
id, globalAttribute] :
attributes[
nullptr] ) {
106 if ( globalAttribute->name == attributeName ) {
107 attribute = globalAttribute;
112 throw std::runtime_error(
"DynamicDataProvider: unknown global attribute '" + attributeName +
"'");
117 globals[globalAttribute->index] = value;
122 if ( !value.has_value() ) {
123 throw std::runtime_error(
"DynamicDataProvider: failed to evaluate global '" + attributeName +
"'");
127 else if ( instanceIdStr.empty() ) {
128 throw std::runtime_error(
"DynamicDataProvider: instance id required when node id is provided");
140 throw std::runtime_error(
"DynamicDataProvider: first row for instance '" + instanceIdStr +
"' must reference a process node, got '" + nodeId +
"'");
149 if ( initialization.empty() ) {
158 if ( !extensionElements->attributeRegistry.contains(attributeName) ) {
159 throw std::runtime_error(
"DynamicDataProvider: node '" + nodeId +
"' has no attribute '" + attributeName +
"'");
163 if ( attribute->expression ) {
164 throw std::runtime_error(
"DynamicDataProvider: value of attribute '" + attributeName +
"' is initialized by expression and must not be provided explicitly");
169 if ( !disclosureStr.empty() ) {
179 if (disclosureTime == 0) {
181 instance.data[attribute] = value;
200 effectiveInstantiation = std::max(effectiveInstantiation,
disclosure.at(
id).at(instance.process));
214 auto pos = initialization.find(
":=");
215 if ( pos == std::string::npos ) {
216 throw std::runtime_error(
"DynamicDataProvider: initialization must be in format 'attribute := expression', got '" + initialization +
"'");
219 std::string attributeName = initialization.substr(0, pos);
220 std::string expression = initialization.substr(pos + 2);
223 auto trimStart = attributeName.find_first_not_of(
" \t");
224 auto trimEnd = attributeName.find_last_not_of(
" \t");
225 if ( trimStart == std::string::npos ) {
226 throw std::runtime_error(
"DynamicDataProvider: empty attribute name in initialization '" + initialization +
"'");
228 attributeName = attributeName.substr(trimStart, trimEnd - trimStart + 1);
230 trimStart = expression.find_first_not_of(
" \t");
231 trimEnd = expression.find_last_not_of(
" \t");
232 if ( trimStart == std::string::npos ) {
233 throw std::runtime_error(
"DynamicDataProvider: empty expression in initialization '" + initialization +
"'");
235 expression = expression.substr(trimStart, trimEnd - trimStart + 1);
237 return {attributeName, expression};
264 auto parentNode = childNode->parent;
265 if ( !
disclosure[instanceId].contains(parentNode) ) {
266 throw std::runtime_error(
"DynamicDataProvider: disclosure for '" + node->
id +
"' given before parent '" + parentNode->id +
"'");
268 effectiveDisclosure = std::max(effectiveDisclosure,
disclosure[instanceId][parentNode]);
272 if ( !
disclosure[instanceId].contains(node) ) {
273 disclosure[instanceId][node] = effectiveDisclosure;
279 return effectiveDisclosure;
312 for (
auto& [
id, instance] :
instances ) {
314 auto instantiationTime = instance.data[timestampAttribute];
315 scenario->addInstance(instance.process,
id, instantiationTime);
316 for (
auto& [attribute, value] : instance.data ) {
317 scenario->setValue(
id, attribute, value);
321 for (
auto& [instanceId, nodes] :
disclosure ) {
322 for (
auto& [node, disclosureTime] : nodes ) {
323 scenario->setDisclosure(instanceId, node, disclosureTime);
328 for (
auto& pending : pendings) {
329 scenario->addPendingDisclosure(instanceId, {pending.attribute, pending.disclosureTime, pending.value});
333 scenario->revealData(0);