12 , attributeRegistry(attributeRegistry)
16 strutil::replace_all( input,
"∈",
" in ");
18 if ( strutil::contains(input,
" in ") ) {
19 parseEnumeration(input);
21 else if ( !strutil::contains(input,
"<") ) {
22 throw std::runtime_error(
"Choice: no enumeration or bounds given in '" + input +
"'");
25 strutil::replace_all( input,
"|",
" divides ");
26 auto [bounds,discretizer] = [&input]() -> std::pair<std::string, std::string> {
27 if ( !strutil::contains(input,
" divides ") ) {
33 auto pos = input.rfind(
',');
34 if ( pos == std::string::npos ) {
35 throw std::runtime_error(
"Choice: illegal condition '" + input +
"'");
38 strutil::trim_copy(input.substr(0, pos)),
39 strutil::trim_copy(input.substr(pos + 1))
45 if ( !discretizer.empty() ) {
46 parseDiscretizer(discretizer);
51 throw std::runtime_error(
"Choice: no enumeration provided for string");
54 throw std::runtime_error(
"Choice: attribute is a collection");
60void Choice::parseEnumeration(
const std::string& input) {
61 auto parts = strutil::split(input,
" in ");
62 if ( parts.size() != 2 ) {
63 throw std::runtime_error(
"Choice: illegal enumeration '" + input +
"'");
66 std::string attributeName = strutil::trim_copy(parts.front());
67 if ( attributeName ==
"" ) {
68 throw std::runtime_error(
"Choice: unable to determine attribute name");
72 auto rhs = strutil::trim_copy(parts.back());
74 if ( (rhs.front() ==
'[' && rhs.back() ==
']') || (rhs.front() ==
'{' && rhs.back() ==
'}') ) {
75 auto alternatives = strutil::split(
encodeCollection( rhs.substr(1, rhs.size()-2) ),
',' );
76 for (
auto& alternative : alternatives ) {
78 for (
auto dependency :
enumeration.back()->inputs ) {
83 throw std::runtime_error(
"Choice: empty enumeration");
87 throw std::runtime_error(
"Choice: invalid enumeration '" + rhs +
"'");
91void Choice::parseBounds(
const std::string& input) {
93 auto conditions = strutil::split(input,
'<');
94 if ( conditions.size() == 3 ) {
95 bool strictLB =
false;
97 if ( conditions[1][0] ==
'=' ) {
99 conditions[1].erase(0, 1);
106 std::make_unique<Expression>(strutil::trim_copy(conditions[0]),
attributeRegistry),
109 for (
auto dependency :
lowerBound.value().first->inputs ) {
114 std::string attributeName = strutil::trim_copy(conditions[1]);
115 if ( attributeName ==
"" ) {
116 throw std::runtime_error(
"Choice: unable to determine attribute name");
120 bool strictUB =
false;
121 if ( conditions[2][0] ==
'=' ) {
123 conditions[2].erase(0, 1);
131 std::make_unique<Expression>(strutil::trim_copy(conditions[2]),
attributeRegistry),
134 for (
auto dependency :
upperBound.value().first->inputs ) {
141 throw std::runtime_error(
"Choice: condition '" + input +
"' is unbounded");
145void Choice::parseDiscretizer(
const std::string& input) {
146 auto parts = strutil::split(input,
" divides ");
147 std::string attributeName = strutil::trim_copy(parts[1]);
149 throw std::runtime_error(
"Choice: inconsistent attribute name '" + attributeName +
"' in '" + input +
"'");
152 for (
auto dependency :
multipleOf->inputs ) {
158template <
typename DataType>
164 BPMNOS::number min = LB->execute(status,data,globals).value_or(std::numeric_limits<BPMNOS::number>::lowest());
170 BPMNOS::number max = UB->execute(status,data,globals).value_or(std::numeric_limits<BPMNOS::number>::max());
176 min = std::ceil((
double)min);
177 max = std::floor((
double)max);
187template <
typename DataType>
190 std::vector<BPMNOS::number> allowedValues;
193 auto allowedValue = alternative->execute(status,data,globals);
194 if ( allowedValue.has_value() ) {
195 allowedValues.push_back( allowedValue.value() );
200 auto [LB, UB] =
getBounds(status, data, globals);
201 auto discretizer =
multipleOf->execute(status, data, globals);
202 if ( !discretizer.has_value() ) {
207 throw std::runtime_error(
"Choice: cannot determine discretizer for '" +
multipleOf->expression +
"'");
211 for (
BPMNOS::number value = (
double)DELTA * std::ceil((
double)LB / (
double)DELTA); value <= UB; value += DELTA ) {
212 allowedValues.push_back(value);
216 return allowedValues;
#define BPMNOS_NUMBER_PRECISION
bool isImmutable
Flag indicating whether attribute value may be changed by operator, choice, or intermediate catch eve...
std::optional< std::pair< std::unique_ptr< Expression >, bool > > upperBound
std::set< const Attribute * > dependencies
Choice(XML::bpmnos::tDecision *decision, const AttributeRegistry &attributeRegistry)
std::optional< std::pair< std::unique_ptr< Expression >, bool > > lowerBound
std::pair< BPMNOS::number, BPMNOS::number > getBounds(const BPMNOS::Values &status, const DataType &data, const BPMNOS::Values &globals) const
Returns the minimal and maximal value the attribute may take.
std::vector< BPMNOS::number > getEnumeration(const BPMNOS::Values &status, const DataType &data, const BPMNOS::Values &globals) const
Returns the allowed values the attribute may take.
const AttributeRegistry & attributeRegistry
std::unique_ptr< Expression > multipleOf
std::vector< std::unique_ptr< Expression > > enumeration
Attribute & condition
Attribute value can be expected to be of type 'std::string'.
std::string encodeQuotedStrings(std::string text)
std::string encodeCollection(std::string text)
Function to replace a collection that is not preceded by an alphanumeric or underscore.
BPMNOS_NUMBER_TYPE number