26inline logic_real string_to_real(
const std::string& s) {
27 #if !defined(__GNUC__) && !defined(_MSC_VER)
28 #pragma STDC FENV_ACCESS ON
30 int old = std::fegetround();
31 int r = std::fesetround(FE_DOWNWARD);
33 double lb = std::strtod(s.c_str(),
nullptr);
34 r = std::fesetround(FE_UPWARD);
36 double ub = std::strtod(s.c_str(),
nullptr);
38 return battery::make_tuple(lb, ub);
41template <
class Allocator>
43 using allocator_type = Allocator;
44 using F = TFormula<allocator_type>;
45 using SV = peg::SemanticValues;
46 using Set = logic_set<F>;
47 using So = Sort<allocator_type>;
48 using bstring = battery::string<Allocator>;
49 using FSeq =
typename F::Sequence;
51 std::map<std::string, F> params;
52 std::map<std::string, int> arrays;
59 std::set<std::string> ignored_annotations;
61 enum class TableKind {
71 battery::shared_ptr<F, allocator_type> parse(
const std::string& input) {
72 peg::parser parser(R
"(
73 Statements <- (PredicateDecl / VariableDecl / VarArrayDecl / ParameterDecl / ConstraintDecl / SolveItem / Comment)+
75 Literal <- Boolean / Real / Integer / ArrayAccess / VariableLit / Set
76 RangeLiteral <- SetRange / Literal
77 InnerRangeLiteral <- InnerSetRange / Literal
79 VariableLit <- Identifier
80 Identifier <- < [a-zA-Z_][a-zA-Z0-9_]* >
81 Boolean <- < 'true' / 'false' >
85 / [+-]? [0-9]+ (('.' (&'..' / !'.') [0-9]*) / ([Ee][+-]?[0-9]+)) ) >
86 Integer <- < [+-]? [0-9]+ >
87 Set <- '{' '}' / '{' InnerRangeLiteral (',' InnerRangeLiteral)* '}'
88 InnerSetRange <- Literal '..' Literal
89 SetRange <- InnerSetRange
90 ArrayAccess <- Identifier '[' (VariableLit / Integer) ']'
92 VariableDecl <- 'var' ValueType ':' Identifier Annotations ('=' Literal)? ';'
93 VarArrayDecl <- 'array' '[' IndexSet ']' 'of' 'var' ValueType ':' Identifier Annotations ('=' LiteralArray)? ';'
95 SetValue <- 'set' 'of' (SetRange / Set)
103 RealType <- 'float' / 'real'
105 SetType <- 'set' 'of' Type
106 Type <- IntType / RealType / BoolType / SetType
108 Annotation <- Identifier ('(' Parameter (',' Parameter)* ')')?
109 Annotations <- ('::' Annotation)*
111 ConstraintDecl <- 'constraint' (PredicateCall / Boolean) Annotations ';'
113 LiteralInExpression <- RangeLiteral !'('
114 FunctionCall <- Identifier '(' Parameter (',' Parameter )* ')'
115 Parameter <- LiteralInExpression / FunctionCall / LiteralArray
116 PredicateCall <- Identifier '(' Parameter (',' Parameter)* ')'
118 PredicateDecl <- 'predicate' Identifier '(' (!')' .)* ')' ';'
120 MinimizeItem <- 'minimize' RangeLiteral
121 MaximizeItem <- 'maximize' RangeLiteral
122 SatisfyItem <- 'satisfy'
123 SolveItem <- 'solve' SearchAnnotations (MinimizeItem / MaximizeItem / SatisfyItem) ';'
125 SearchAnnotations <- ('::' SearchAnnotation)*
126 SearchAnnotation <- SeqSearch / BaseSearch
127 SeqSearch <- 'seq_search' '(' '[' SearchAnnotation (',' SearchAnnotation)* ']' ')'
128 BaseSearch <- ('int_search' / 'bool_search' / 'set_search') '(' (VariableLit / LiteralArray) ',' Identifier ',' Identifier ',' Identifier ')'
130 LiteralArray <- '[]' / '[' RangeLiteral (',' RangeLiteral)* ']'
131 ParameterExpr <- RangeLiteral / LiteralArray
132 IndexSet <- '1' '..' Integer
133 ArrayType <- 'array' '[' IndexSet ']' 'of' Type
134 ParameterType <- Type / ArrayType
135 ParameterDecl <- ParameterType ':' Identifier '=' ParameterExpr ';'
137 ~Comment <- '%' [^\n\r]* [ \n\r\t]*
138 %whitespace <- [ \n\r\t]*
141 assert(static_cast<bool>(parser) ==
true);
143 parser[
"Integer"] = [](
const SV &sv) {
return F::make_z(sv.token_to_number<logic_int>()); };
144 parser[
"Real"] = [](
const SV &sv) {
return F::make_real(string_to_real(sv.token_to_string())); };
145 parser[
"Boolean"] = [](
const SV &sv) {
return sv.token_to_string() ==
"true" ? F::make_true() : F::make_false(); };
146 parser[
"Identifier"] = [](
const SV &sv) {
return sv.token_to_string(); };
147 parser[
"Set"] = [
this](
const SV &sv) {
return make_set_literal(sv); };
148 parser[
"InnerSetRange"] = [
this](
const SV &sv) {
return battery::make_tuple(f(sv[0]), f(sv[1])); };
149 parser[
"SetRange"] = [
this](
const SV &sv) {
return F::make_set(Set({itv(sv[0])})); };
150 parser[
"ArrayAccess"] = [
this](
const SV &sv) {
return make_access_literal(sv); };
151 parser[
"LiteralArray"] = [](
const SV &sv) {
return sv; };
152 parser[
"ParameterDecl"] = [
this] (
const SV &sv) {
return make_parameter_decl(sv); };
153 parser[
"PredicateDecl"] = [
this] (
const SV &sv) {
return F(); };
154 parser[
"VariableLit"] = [](
const SV &sv) {
return F::make_lvar(UNTYPED, LVar<Allocator>(std::any_cast<std::string>(sv[0]))); };
155 parser[
"IntType"] = [](
const SV &sv) {
return So(So::Int); };
156 parser[
"RealType"] = [](
const SV &sv) {
return So(So::Real); };
157 parser[
"BoolType"] = [](
const SV &sv) {
return So(So::Bool); };
158 parser[
"SetType"] = [](
const SV &sv) {
return So(So::Set, std::any_cast<Sort<Allocator>>(sv[0])); };
159 parser[
"Annotations"] = [](
const SV &sv) {
return sv; };
160 parser[
"Annotation"] = [](
const SV &sv) {
return sv; };
162 parser[
"SetValue"] = [](
const SV &sv) {
return F::make_set(Set({battery::make_tuple(F::make_set(Set{}), f(sv[0]))})); };
163 parser[
"VariableDecl"] = [
this](
const SV &sv) {
return make_variable_init_decl(sv); };
164 parser[
"VarArrayDecl"] = [
this](
const SV &sv) {
return make_variable_array_decl(sv); };
165 parser[
"ConstraintDecl"] = [
this](
const SV &sv) {
return update_with_annotations(sv, f(sv[0]), std::any_cast<SV>(sv[1])); };
166 parser[
"FunctionCall"] = [
this](
const SV &sv) {
return function_call(sv); };
167 parser[
"PredicateCall"] = [
this](
const SV &sv) {
return predicate_call(sv); };
168 parser[
"Statements"] = [
this](
const SV &sv) {
return make_statements(sv); };
169 parser[
"MinimizeItem"] = [](
const SV &sv) {
return F::make_unary(MINIMIZE, f(sv[0])); };
170 parser[
"MaximizeItem"] = [](
const SV &sv) {
return F::make_unary(MAXIMIZE, f(sv[0])); };
171 parser[
"SatisfyItem"] = [](
const SV &sv) {
return F(); };
172 parser[
"SolveItem"] = [
this](
const SV &sv) {
return make_solve_item(sv);};
173 parser[
"SearchAnnotations"] = [
this](
const SV &sv) {
return make_search_annotations(sv);};
174 parser[
"BaseSearch"] = [
this](
const SV &sv) {
return make_base_search(sv);};
175 parser[
"SeqSearch"] = [
this](
const SV &sv) {
return make_seq_search(sv);};
176 parser.set_logger([](
size_t line,
size_t col,
const std::string& msg,
const std::string &rule) {
177 std::cerr << line <<
":" << col <<
": " << msg <<
"\n";
181 if(parser.parse(input.c_str(), f) && !error) {
182 return battery::make_shared<TFormula<Allocator>, Allocator>(std::move(f));
190 static F f(
const std::any& any) {
191 return std::any_cast<F>(any);
194 static battery::tuple<F, F> itv(
const std::any& any) {
195 return std::any_cast<battery::tuple<F, F>>(any);
198 F make_error(
const SV& sv,
const std::string& msg) {
200 std::cerr << sv.line_info().first <<
":" << sv.line_info().second <<
":" << msg << std::endl;
203 return F::make_false();
206 F make_arity_error(
const SV& sv, Sig sig,
int expected,
int obtained) {
207 return make_error(sv,
"The symbol `" + std::string(string_of_sig(sig)) +
208 "` expects `" + std::to_string(expected) +
"` parameters" +
209 ", but we got `" + std::to_string(obtained) +
"` parameters.");
212 F make_set_literal(
const SV& sv) {
214 for(
int i = 0; i < sv.size(); ++i) {
216 auto range = std::any_cast<battery::tuple<F,F>>(sv[i]);
217 set.push_back(range);
219 catch(std::bad_any_cast) {
220 bool element_added =
false;
221 auto element = f(sv[i]);
222 if(element.is(F::Z) && set.size() > 0) {
223 auto& ub = battery::get<1>(set.back());
225 return make_error(sv,
"Elements in a set are expected to be all of the same type.");
227 else if(ub.z() == element.z() - 1) {
228 ub.z() = element.z();
229 element_added =
true;
232 else if(element.is(F::LV)) {
233 std::string name(element.lv().data());
234 if(params.contains(name)) {
235 set.push_back(battery::make_tuple(params[name], params[name]));
236 element_added =
true;
239 return make_error(sv,
"Undeclared parameter `" + name +
"`.");
243 set.push_back(battery::make_tuple(element, element));
247 return F::make_set(set);
250 F make_access_literal(
const SV& sv) {
251 auto name = std::any_cast<std::string>(sv[0]);
252 auto index = f(sv[1]);
255 idx =
static_cast<int>(index.z());
257 else if(index.is(F::LV)) {
258 if(params.contains(index.lv().data())) {
259 auto pindex = params[index.lv().data()];
260 if(pindex.is(F::Z)) {
261 idx =
static_cast<int>(pindex.z());
266 return make_error(sv,
"Given `a[b]`, `b` must be an integer or an integer parameter.");
268 auto access_var = make_array_access(name, idx-1);
269 if(params.contains(access_var)) {
270 return params[access_var];
273 return F::make_lvar(UNTYPED, access_var);
277 F make_parameter_decl(
const SV& sv) {
278 std::string identifier(std::any_cast<std::string>(sv[1]));
280 if(params.contains(identifier)) {
281 return make_error(sv, (
"Parameter `" + identifier +
"` already declared.").c_str());
284 params[identifier] = f(sv[2]);
286 }
catch(std::bad_any_cast) {
287 auto array = std::any_cast<SV>(sv[2]);
288 arrays[identifier] =
static_cast<int>(array.size());
289 for(
int i = 0; i < static_cast<int>(array.size()); ++i) {
290 auto id = make_array_access(identifier, i);
291 params[id] = f(array[i]);
294 return F::make_true();
297 F make_variable_array_decl(
const SV& sv) {
298 int arraySize =
static_cast<int>(f(sv[0]).z());
299 auto name = std::any_cast<std::string>(sv[2]);
300 arrays[name] = arraySize;
301 battery::vector<F, Allocator> decl;
302 for(
int i = 0; i < arraySize; ++i) {
303 decl.push_back(make_variable_decl(sv, make_array_access(name, i), sv[1], sv[3]));
306 auto array = resolve_array(sv, sv[4]);
307 if(!array.is(F::Seq)) {
310 for(
int i = 0; i < array.seq().size(); ++i) {
311 decl.push_back(F::make_binary(
312 F::make_lvar(UNTYPED, LVar<Allocator>(make_array_access(name, i))),
317 return F::make_nary(AND, std::move(decl));
320 F update_with_annotations(
const SV& sv, F formula,
const SV& annots) {
321 for(
int i = 0; i < annots.size(); ++i) {
322 auto annot = std::any_cast<SV>(annots[i]);
323 auto name = std::any_cast<std::string>(annot[0]);
324 if(name ==
"abstract") {
325 AType ty = f(annot[1]).z();
328 else if(name ==
"is_defined_var") {}
329 else if(name ==
"defines_var") {}
330 else if(name ==
"var_is_introduced") {}
331 else if(name ==
"output_var" && formula.is(F::E)) {
332 output.
add_var(battery::get<0>(formula.exists()));
334 else if(name ==
"output_array" && formula.is(F::E)) {
335 auto array_name = std::any_cast<std::string>(sv[2]);
336 auto dims = std::any_cast<SV>(annot[1]);
337 output.
add_array_var(array_name, battery::get<0>(formula.exists()), dims);
340 if(!ignored_annotations.contains(name)) {
341 ignored_annotations.insert(name);
342 std::cerr <<
"% WARNING: Annotation " + name +
" is unknown and was ignored." << std::endl;
346 return std::move(formula);
349 F make_binary(Sig sig,
const SV &sv) {
351 return make_arity_error(sv, sig, 2,
static_cast<int>(sv.size()) - 1);
353 return F::make_binary(f(sv[1]), sig, f(sv[2]));
356 F make_unary_fun_eq(Sig sig,
const SV &sv, Sig eq_kind = EQ) {
358 return make_arity_error(sv, sig, 1,
static_cast<int>(sv.size()) - 2);
360 auto fun = F::make_unary(sig, f(sv[1]));
361 return F::make_binary(fun, eq_kind, f(sv[2]));
364 F make_unary_fun(Sig sig,
const SV &sv) {
366 return make_arity_error(sv, sig, 1,
static_cast<int>(sv.size()) - 1);
368 return F::make_unary(sig, f(sv[1]));
371 F make_binary_fun_eq(Sig sig,
const SV &sv, Sig eq_kind = EQ) {
373 return make_arity_error(sv, sig, 2,
static_cast<int>(sv.size()) - 2);
375 auto left = F::make_binary(f(sv[1]), sig, f(sv[2]));
376 auto right = f(sv[3]);
377 if(eq_kind == EQUIV && right.is_true()) {
380 return F::make_binary(left, eq_kind, right);
383 F make_binary_fun(Sig sig,
const SV& sv) {
385 return make_arity_error(sv, sig, 2,
static_cast<int>(sv.size()) - 1);
387 return F::make_binary(f(sv[1]), sig, f(sv[2]));
390 F make_nary_fun(Sig sig,
const SV &sv) {
392 for(
int i = 1; i < sv.size(); ++i) {
393 seq.push_back(f(sv[i]));
395 return F::make_nary(sig, std::move(seq));
398 F make_float_in(
const SV &sv) {
399 return F::make_binary(
400 F::make_binary(f(sv[1]), GEQ, f(sv[2])),
402 F::make_binary(f(sv[1]), LEQ, f(sv[3])));
405 F make_log(
int base,
const SV &sv) {
406 return F::make_binary(f(sv[1]), LOG, F::make_z(base));
409 F make_log_eq(
int base,
const SV &sv) {
410 return F::make_binary(make_log(base, sv), EQ, f(sv[2]));
413 F predicate_call(
const SV &sv) {
414 auto name = std::any_cast<std::string>(sv[0]);
415 if (name ==
"int_le") {
return make_binary(LEQ, sv); }
416 if (name ==
"int_lt") {
return make_binary(LT, sv); }
417 if (name ==
"int_ge") {
return make_binary(GEQ, sv); }
418 if (name ==
"int_gt") {
return make_binary(GT, sv); }
419 if (name ==
"int_eq") {
return make_binary(EQ, sv); }
420 if (name ==
"int_ne") {
return make_binary(NEQ, sv); }
421 if (name ==
"int_abs") {
return make_unary_fun_eq(ABS, sv); }
422 if (name ==
"int_neg") {
return make_unary_fun_eq(NEG, sv); }
423 if (name ==
"int_div") {
return make_binary_fun_eq(EDIV, sv); }
424 if (name ==
"int_mod") {
return make_binary_fun_eq(EMOD, sv); }
425 if (name ==
"int_plus") {
return make_binary_fun_eq(ADD, sv); }
426 if (name ==
"int_minus") {
return make_binary_fun_eq(SUB, sv); }
427 if (name ==
"int_pow") {
return make_binary_fun_eq(POW, sv); }
428 if (name ==
"int_times") {
return make_binary_fun_eq(MUL, sv); }
429 if (name ==
"int_max") {
return make_binary_fun_eq(MAX, sv); }
430 if (name ==
"int_min") {
return make_binary_fun_eq(MIN, sv); }
431 if (name ==
"int_eq_reif") {
return make_binary_fun_eq(EQ, sv, EQUIV); }
432 if (name ==
"int_le_reif") {
return make_binary_fun_eq(LEQ, sv, EQUIV); }
433 if (name ==
"int_lt_reif") {
return make_binary_fun_eq(LT, sv, EQUIV); }
434 if (name ==
"int_ne_reif") {
return make_binary_fun_eq(NEQ, sv, EQUIV); }
435 if (name ==
"bool2int") {
return make_binary(EQ, sv); }
436 if (name ==
"bool_eq") {
return make_binary(EQ, sv); }
437 if (name ==
"bool_le") {
return make_binary(LEQ, sv); }
438 if (name ==
"bool_lt") {
return make_binary(LT, sv); }
439 if (name ==
"bool_eq_reif") {
return make_binary_fun_eq(EQ, sv, EQUIV); }
440 if (name ==
"bool_le_reif") {
return make_binary_fun_eq(LEQ, sv, EQUIV); }
441 if (name ==
"bool_lt_reif") {
return make_binary_fun_eq(LT, sv, EQUIV); }
442 if (name ==
"bool_and") {
return make_binary_fun_eq(AND, sv, EQUIV); }
443 if (name ==
"bool_not") {
444 if(sv.size() == 3) {
return make_binary(XOR, sv); }
445 else {
return make_unary_fun(NOT, sv); }
447 if (name ==
"bool_or") {
return make_binary_fun_eq(OR, sv, EQUIV); }
448 if (name ==
"nbool_and") {
return make_nary_fun(AND, sv); }
449 if (name ==
"nbool_or") {
return make_nary_fun(OR, sv); }
450 if (name ==
"nbool_equiv") {
return make_nary_fun(EQUIV, sv); }
451 if (name ==
"bool_xor") {
452 if(sv.size() == 3) {
return make_binary(XOR, sv); }
453 else {
return make_binary_fun_eq(XOR, sv, EQUIV); }
455 if (name ==
"set_card") {
return make_unary_fun_eq(CARD, sv); }
456 if (name ==
"set_diff") {
return make_binary_fun_eq(DIFFERENCE, sv); }
457 if (name ==
"set_eq") {
return make_binary(EQ, sv); }
458 if (name ==
"set_eq_reif") {
return make_binary_fun_eq(EQ, sv, EQUIV); }
459 if (name ==
"set_in") {
return make_binary(IN, sv); }
460 if (name ==
"set_in_reif") {
return make_binary_fun_eq(IN, sv, EQUIV); }
461 if (name ==
"set_intersect") {
return make_binary_fun_eq(INTERSECTION, sv, EQUIV); }
462 if (name ==
"set_union") {
return make_binary_fun_eq(UNION, sv, EQUIV); }
463 if (name ==
"set_ne") {
return make_binary(NEQ, sv); }
464 if (name ==
"set_ne_reif") {
return make_binary_fun_eq(NEQ, sv, EQUIV); }
465 if (name ==
"set_subset") {
return make_binary(SUBSETEQ, sv); }
466 if (name ==
"set_subset_reif") {
return make_binary_fun_eq(SUBSETEQ, sv, EQUIV); }
467 if (name ==
"set_superset") {
return make_binary(SUPSETEQ, sv); }
468 if (name ==
"set_symdiff") {
return make_binary_fun_eq(SYMMETRIC_DIFFERENCE, sv, EQUIV); }
469 if (name ==
"set_le") {
return make_binary(LEQ, sv); }
470 if (name ==
"set_le_reif") {
return make_binary_fun_eq(LEQ, sv, EQUIV); }
471 if (name ==
"set_lt") {
return make_binary(LT, sv); }
472 if (name ==
"set_lt_reif") {
return make_binary_fun_eq(LT, sv, EQUIV); }
473 if (name ==
"float_abs") {
return make_binary_fun_eq(ABS, sv); }
474 if (name ==
"float_neg") {
return make_binary_fun_eq(NEG, sv); }
475 if (name ==
"float_plus") {
return make_binary_fun_eq(ADD, sv); }
476 if (name ==
"float_minus") {
return make_binary_fun_eq(SUB, sv); }
477 if (name ==
"float_times") {
return make_binary_fun_eq(MUL, sv); }
478 if (name ==
"float_acos") {
return make_unary_fun_eq(ACOS, sv); }
479 if (name ==
"float_acosh") {
return make_unary_fun_eq(ACOSH, sv); }
480 if (name ==
"float_asin") {
return make_unary_fun_eq(ASIN, sv); }
481 if (name ==
"float_asinh") {
return make_unary_fun_eq(ASINH, sv); }
482 if (name ==
"float_atan") {
return make_unary_fun_eq(ATAN, sv); }
483 if (name ==
"float_atanh") {
return make_unary_fun_eq(ATANH, sv); }
484 if (name ==
"float_cos") {
return make_unary_fun_eq(COS, sv); }
485 if (name ==
"float_cosh") {
return make_unary_fun_eq(COSH, sv); }
486 if (name ==
"float_sin") {
return make_unary_fun_eq(SIN, sv); }
487 if (name ==
"float_sinh") {
return make_unary_fun_eq(SINH, sv); }
488 if (name ==
"float_tan") {
return make_unary_fun_eq(TAN, sv); }
489 if (name ==
"float_tanh") {
return make_unary_fun_eq(TANH, sv); }
490 if (name ==
"float_div") {
return make_binary(DIV, sv); }
491 if (name ==
"float_eq") {
return make_binary(EQ, sv); }
492 if (name ==
"float_eq_reif") {
return make_binary_fun_eq(EQ, sv, EQUIV); }
493 if (name ==
"float_le") {
return make_binary(LEQ, sv); }
494 if (name ==
"float_le_reif") {
return make_binary_fun_eq(LEQ, sv, EQUIV); }
495 if (name ==
"float_ne") {
return make_binary(NEQ, sv); }
496 if (name ==
"float_ne_reif") {
return make_binary_fun_eq(NEQ, sv, EQUIV); }
497 if (name ==
"float_lt") {
return make_binary(LT, sv); }
498 if (name ==
"float_lt_reif") {
return make_binary_fun_eq(LT, sv, EQUIV); }
499 if (name ==
"float_in") {
return make_float_in(sv); }
500 if (name ==
"float_in_reif") {
501 return F::make_binary(make_float_in(sv), EQUIV, f(sv[4]));
503 if (name ==
"float_log10") {
return make_log_eq(10, sv); }
504 if (name ==
"float_log2") {
return make_log_eq(2, sv); }
505 if (name ==
"float_min") {
return make_binary_fun_eq(MIN, sv); }
506 if (name ==
"float_max") {
return make_binary_fun_eq(MAX, sv); }
507 if (name ==
"float_exp") {
return make_unary_fun_eq(EXP, sv); }
508 if (name ==
"float_ln") {
return make_unary_fun_eq(LN, sv); }
509 if (name ==
"float_pow") {
return make_binary_fun_eq(POW, sv); }
510 if (name ==
"float_sqrt") {
return make_unary_fun_eq(SQRT, sv); }
511 if (name ==
"int2float") {
return make_binary(EQ, sv); }
512 if (name ==
"array_int_element" || name ==
"array_var_int_element"
513 || name ==
"array_bool_element" || name ==
"array_var_bool_element"
514 || name ==
"array_set_element" || name ==
"array_var_set_element"
515 || name ==
"array_float_element" || name ==
"array_var_float_element")
517 return make_element_constraint(name, sv);
519 if (name ==
"int_lin_eq" || name ==
"bool_lin_eq" || name ==
"float_lin_eq" ||
520 name ==
"int_lin_eq_reif" || name ==
"bool_lin_eq_reif" || name ==
"float_lin_eq_reif")
522 return make_linear_constraint(name, EQ, sv);
524 if (name ==
"int_lin_le" || name ==
"bool_lin_le" || name ==
"float_lin_le" ||
525 name ==
"int_lin_le_reif" || name ==
"bool_lin_le_reif" || name ==
"float_lin_le_reif")
527 return make_linear_constraint(name, LEQ, sv);
529 if (name ==
"int_lin_ne" || name ==
"bool_lin_ne" || name ==
"float_lin_ne" ||
530 name ==
"int_lin_ne_reif" || name ==
"bool_lin_ne_reif" || name ==
"float_lin_ne_reif")
532 return make_linear_constraint(name, NEQ, sv);
534 if (name ==
"array_bool_and") {
return make_boolean_constraint(name, AND, sv); }
535 if (name ==
"array_bool_or") {
return make_boolean_constraint(name, OR, sv); }
536 if (name ==
"array_bool_xor") {
return make_boolean_constraint(name, XOR, sv); }
537 if (name ==
"bool_clause" || name ==
"bool_clause_reif") {
538 return make_boolean_clause(name, sv);
540 if(name ==
"turbo_fzn_table_bool" || name ==
"turbo_fzn_table_int") {
541 return make_table_constraint(name, sv, TableKind::PLAIN);
543 if(name ==
"turbo_fzn_short_table_int" || name ==
"turbo_fzn_short_table_set_of_int") {
544 return make_table_constraint(name, sv, TableKind::SHORT);
546 if(name ==
"turbo_fzn_basic_table_int" || name ==
"turbo_fzn_basic_table_set_of_int") {
547 return make_table_constraint(name, sv, TableKind::BASIC);
549 if(name ==
"turbo_fzn_compressed_table_int") {
550 return make_table_constraint(name, sv, TableKind::COMPRESSED);
552 return make_error(sv,
"Unknown predicate `" + name +
"`");
555 F function_call(
const SV &sv) {
556 auto name = std::any_cast<std::string>(sv[0]);
560 auto p = predicate_call(sv);
567 if(name ==
"int_abs") {
return make_unary_fun(ABS, sv); }
568 if (name ==
"int_neg") {
return make_unary_fun(NEG, sv); }
569 if (name ==
"int_div") {
return make_binary_fun(EDIV, sv); }
570 if (name ==
"int_mod") {
return make_binary_fun(EMOD, sv); }
571 if (name ==
"int_plus") {
return make_binary_fun(ADD, sv); }
572 if (name ==
"int_minus") {
return make_binary_fun(SUB, sv); }
573 if (name ==
"int_pow") {
return make_binary_fun(POW, sv); }
574 if (name ==
"int_times") {
return make_binary_fun(MUL, sv); }
575 if (name ==
"int_max") {
return make_binary_fun(MAX, sv); }
576 if (name ==
"int_min") {
return make_binary_fun(MIN, sv); }
577 if (name ==
"bool_and") {
return make_binary_fun(AND, sv); }
578 if (name ==
"bool_not") {
return make_unary_fun(NOT, sv); }
579 if (name ==
"bool_or") {
return make_binary_fun(OR, sv); }
580 if (name ==
"bool_xor") {
return make_binary_fun(XOR, sv); }
581 if (name ==
"set_card") {
return make_unary_fun(CARD, sv); }
582 if (name ==
"set_diff") {
return make_binary_fun(DIFFERENCE, sv); }
583 if (name ==
"set_intersect") {
return make_binary_fun(INTERSECTION, sv); }
584 if (name ==
"set_union") {
return make_binary_fun(UNION, sv); }
585 if (name ==
"set_symdiff") {
return make_binary_fun(SYMMETRIC_DIFFERENCE, sv); }
586 if (name ==
"float_abs") {
return make_binary_fun(ABS, sv); }
587 if (name ==
"float_neg") {
return make_binary_fun(NEG, sv); }
588 if (name ==
"float_plus") {
return make_binary_fun(ADD, sv); }
589 if (name ==
"float_minus") {
return make_binary_fun(SUB, sv); }
590 if (name ==
"float_times") {
return make_binary_fun(MUL, sv); }
591 if (name ==
"float_acos") {
return make_unary_fun(ACOS, sv); }
592 if (name ==
"float_acosh") {
return make_unary_fun(ACOSH, sv); }
593 if (name ==
"float_asin") {
return make_unary_fun(ASIN, sv); }
594 if (name ==
"float_asinh") {
return make_unary_fun(ASINH, sv); }
595 if (name ==
"float_atan") {
return make_unary_fun(ATAN, sv); }
596 if (name ==
"float_atanh") {
return make_unary_fun(ATANH, sv); }
597 if (name ==
"float_cos") {
return make_unary_fun(COS, sv); }
598 if (name ==
"float_cosh") {
return make_unary_fun(COSH, sv); }
599 if (name ==
"float_sin") {
return make_unary_fun(SIN, sv); }
600 if (name ==
"float_sinh") {
return make_unary_fun(SINH, sv); }
601 if (name ==
"float_tan") {
return make_unary_fun(TAN, sv); }
602 if (name ==
"float_tanh") {
return make_unary_fun(TANH, sv); }
603 if (name ==
"float_div") {
return make_binary_fun(DIV, sv); }
604 if (name ==
"float_log10") {
return make_log(10, sv); }
605 if (name ==
"float_log2") {
return make_log(2, sv); }
606 if (name ==
"float_min") {
return make_binary_fun(MIN, sv); }
607 if (name ==
"float_max") {
return make_binary_fun(MAX, sv); }
608 if (name ==
"float_exp") {
return make_unary_fun(EXP, sv); }
609 if (name ==
"float_ln") {
return make_unary_fun(LN, sv); }
610 if (name ==
"float_pow") {
return make_binary_fun(POW, sv); }
611 if (name ==
"float_sqrt") {
return make_unary_fun(SQRT, sv); }
612 return make_error(sv,
"Unknown function or predicate symbol `" + name +
"`");
616 F make_statements(
const SV& sv) {
622 for(
int i = 0; i < sv.size(); ++i) {
623 F formula = f(sv[i]);
624 if(!formula.is_true()) {
625 children.push_back(formula);
628 return F::make_nary(AND, std::move(children));
632 F make_existential(
const SV& sv,
const So& ty,
const std::string& name,
const std::any& sv_annots) {
633 auto f = F::make_exists(UNTYPED,
634 LVar<allocator_type>(name.data()),
636 auto annots = std::any_cast<SV>(sv_annots);
637 return update_with_annotations(sv, f, annots);
641 std::string make_array_access(
const S& name,
int i) {
642 return std::string(name.data()) +
"[" + std::to_string(i+1) +
"]";
645 F make_variable_init_decl(
const SV& sv) {
646 auto name = std::any_cast<std::string>(sv[1]);
647 auto var_decl = make_variable_decl(sv, name, sv[0], sv[2]);
649 return F::make_binary(std::move(var_decl), AND,
651 F::make_lvar(UNTYPED, LVar<allocator_type>(name.data())),
656 return std::move(var_decl);
660 F make_variable_decl(
const SV& sv,
const std::string& name,
const std::any& typeVar,
const std::any& annots) {
662 auto ty = std::any_cast<So>(typeVar);
663 return make_existential(sv, ty, name, annots);
665 catch(std::bad_any_cast) {
666 auto typeValue = f(typeVar);
667 auto inConstraint = F::make_binary(F::make_lvar(UNTYPED, LVar<allocator_type>(name.data())), IN, typeValue);
668 auto sort = typeValue.sort();
669 if(!sort.has_value() || !sort->is_set()) {
670 return make_error(sv,
"We only allow type-value of variables to be of type Set.");
672 auto exists = make_existential(sv, *(sort->sub), name, annots);
673 return F::make_binary(std::move(exists), AND, std::move(inConstraint));
677 F make_element_constraint(
const std::string& name,
const SV& sv) {
679 return make_error(sv,
"`" + name +
"` expects 3 parameters, but we got `" + std::to_string(sv.size()-1) +
"` parameters");
681 auto index = f(sv[1]);
682 auto array = resolve_array(sv, sv[2]);
683 if(!array.is(F::Seq)) {
686 auto value = f(sv[3]);
688 for(
int i = 0; i < array.seq().size(); ++i) {
690 seq.push_back(F::make_binary(
691 F::make_binary(index, EQ, F::make_z(i+1)),
693 F::make_binary(array.seq(i), EQ, value)));
695 return F::make_nary(AND, std::move(seq));
698 F resolve_bool(
const SV& sv,
const std::any& any) {
700 auto boolParam = f(any);
701 if(boolParam.is(F::LV)) {
702 std::string paramName(boolParam.lv().data());
703 if(params.contains(paramName)) {
704 boolParam = params[paramName];
707 return make_error(sv,
"Undeclared parameter `" + paramName +
"`.");
710 if(boolParam.is(F::B)) {
714 return make_error(sv,
"Expects a Boolean parameter.");
717 catch(std::bad_any_cast) {
718 return make_error(sv,
"Expects a Boolean parameter.");
724 F resolve_array(
const SV& sv,
const std::any& any) {
727 auto arrayVar = f(any);
728 if(arrayVar.is(F::LV)) {
729 std::string arrayName(arrayVar.lv().data());
730 if(arrays.contains(arrayName)) {
731 int size = arrays[arrayName];
732 for(
int i = 0; i < size; ++i) {
733 auto varName = make_array_access(arrayName, i);
734 if(params.contains(varName)) {
735 seq.push_back(params[varName]);
738 seq.push_back(F::make_lvar(UNTYPED, LVar<allocator_type>(varName.data())));
743 return make_error(sv,
"Unknown array parameter `" + arrayName +
"`");
747 return make_error(sv,
"Expects an array or the name of an array.");
750 catch(std::bad_any_cast) {
752 auto array = std::any_cast<SV>(any);
753 for(
int i = 0; i < array.size(); ++i) {
754 seq.push_back(f(array[i]));
757 catch(std::bad_any_cast) {
758 return make_error(sv,
"Expects an array of valid elements.");
761 return F::make_nary(AND, std::move(seq));
764 F make_linear_constraint(
const std::string& name, Sig sig,
const SV& sv) {
765 if(sv.size() != 4 && sv.size() != 5) {
766 return make_error(sv,
"`" + name +
"` expects 3 (or 4 if reified) parameters, but we got `" + std::to_string(sv.size() - 1) +
"` parameters");
768 auto as = resolve_array(sv, sv[1]);
769 if(!as.is(F::Seq)) {
return as; }
770 auto bs = resolve_array(sv, sv[2]);
771 if(!bs.is(F::Seq)) {
return bs; }
773 if(as.seq().size() != bs.seq().size()) {
774 return make_error(sv,
"`" + name +
"` expects arrays of the same size.");
777 for(
int i = 0; i < as.seq().size(); ++i) {
778 sum.push_back(F::make_binary(as.seq(i), MUL, bs.seq(i)));
782 ? F::make_binary(std::move(sum[0]), sig, c)
783 : F::make_binary(F::make_nary(ADD, std::move(sum)), sig, c);
785 return F::make_binary(f(sv[4]), EQUIV, std::move(linearCons));
788 return std::move(linearCons);
792 F make_boolean_constraint(
const std::string& name, Sig sig,
const SV& sv) {
793 if(sv.size() != 2 && sv.size() != 3) {
794 return make_error(sv,
"`" + name +
"` expects 1 (or 2 if reified) parameters, but we got `" + std::to_string(sv.size() - 1) +
"` parameters");
796 auto array = resolve_array(sv, sv[1]);
797 if(!array.is(F::Seq)) {
return array; }
799 return F::make_binary(f(sv[2]), EQUIV, F::make_nary(sig, array.seq()));
802 return F::make_nary(sig, array.seq());
806 F make_boolean_clause(
const std::string& name,
const SV& sv) {
807 if(sv.size() != 3 && sv.size() != 4) {
808 return make_error(sv,
"`" + name +
"` expects 2 (or 3 if reified) parameters, but we got `" + std::to_string(sv.size() - 1) +
"` parameters");
810 auto as = resolve_array(sv, sv[1]);
811 if(!as.is(F::Seq)) {
return as; }
812 auto bs = resolve_array(sv, sv[2]);
813 if(!bs.is(F::Seq)) {
return bs; }
815 for(
int i = 0; i < bs.seq().size(); ++i) {
816 negs.push_back(F::make_unary(NOT, bs.seq(i)));
818 F clause = F::make_binary(F::make_nary(OR, as.seq()), OR, F::make_nary(OR, negs));
820 return F::make_binary(f(sv[3]), EQUIV, std::move(clause));
823 return std::move(clause);
831 bool is_wildcard(
const F& f, So sort) {
833 return (f.is(F::Z) && f.z() == 2147483647)
834 || (f.is(F::S) && f.s().size() == 0);
836 else if(sort.is_set() && f.is(F::S) && f.s().size() == 1) {
837 auto l = battery::get<0>(f.s()[0]);
838 auto u = battery::get<1>(f.s()[0]);
839 return l.is(F::Z) && u.is(F::Z) && l.z() == 2147483647 && u.z() == 2147483647;
844 So sort_of_table_constraint(
const std::string& name) {
845 if(name ==
"turbo_fzn_table_bool") {
return So(So::Bool); }
846 else if(name ==
"turbo_fzn_table_int") {
return So(So::Int); }
847 else if(name ==
"turbo_fzn_short_table_int") {
return So(So::Int); }
848 else if(name ==
"turbo_fzn_short_table_set_of_int") {
return So(So::Set, So(So::Int)); }
849 else if(name ==
"turbo_fzn_basic_table_int") {
return So(So::Int); }
850 else if(name ==
"turbo_fzn_basic_table_set_of_int") {
return So(So::Set, So(So::Int)); }
851 else if(name ==
"turbo_fzn_compressed_table_int") {
return So(So::Int); }
852 else { printf(
"missing table constraint."); assert(
false);
return So(So::Bool); }
855 F make_table_constraint(
const std::string& name,
const SV& sv, TableKind kind) {
856 bool positive =
true;
859 if(sv.size() != 3 && (name ==
"turbo_fzn_table_bool" || name ==
"turbo_fzn_table_bool")) {
860 return make_error(sv,
"`" + name +
"` expects 2 parameters, but we got `" + std::to_string(sv.size() - 1) +
"` parameters");
864 return make_error(sv,
"`" + name +
"` expects 3 parameters, but we got `" + std::to_string(sv.size() - 1) +
"` parameters");
866 auto boolParam = resolve_bool(sv, sv[1]);
867 if(!boolParam.is(F::B)) {
return boolParam; }
868 positive = boolParam.b();
872 auto header = resolve_array(sv, sv[header_idx]);
873 if(!header.is(F::Seq)) {
return header; }
874 auto table = resolve_array(sv, sv[table_idx]);
875 if(!table.is(F::Seq)) {
return table; }
876 size_t num_t_cols = (kind == TableKind::BASIC) ? header.seq().size() * 2 : header.seq().size();
877 if(table.seq().size() % num_t_cols != 0) {
878 return make_error(sv,
"`" + name +
"` expects the number of variables is equal to the number of columns of the table (or twice for basic tables).");
880 size_t num_cols = header.seq().size();
881 size_t num_rows = table.seq().size() / header.seq().size();
882 So sort = sort_of_table_constraint(name);
884 for(
int i = 0; i < num_rows; ++i) {
886 for(
int z = 0; z < num_cols; ++z) {
887 int j = z * (kind == TableKind::BASIC ? 2 : 1);
888 auto cell = table.seq(i*num_t_cols + j);
889 auto var = header.seq(z);
891 case TableKind::SHORT: {
892 if(is_wildcard(cell, sort)) {
continue; }
894 case TableKind::PLAIN: {
895 if(!cell.is(F::S) && !cell.is(F::Z) && !cell.is(F::B)) {
896 return make_error(sv,
"`" + name +
"` expects each cell to be an integer, a set or a Boolean.");
898 conjuncts.push_back(F::make_binary(var, EQ, cell));
901 case TableKind::COMPRESSED: {
903 return make_error(sv,
"`" + name +
"` expects each cell to be a set.");
905 if(is_wildcard(cell, sort)) {
continue; }
906 conjuncts.push_back(F::make_binary(var, IN, cell));
909 case TableKind::BASIC: {
911 auto u = table.seq(i*num_t_cols + j + 1);
912 if(!l.is(F::S) && !l.is(F::Z) && !u.is(F::S) && !u.is(F::Z)) {
913 return make_error(sv,
"`" + name +
"` expects each cell to be an integer or a set.");
915 if(!is_wildcard(l, sort)) {
917 conjuncts.push_back(F::make_binary(var, GEQ, l));
920 conjuncts.push_back(F::make_binary(var, SUPSETEQ, l));
923 if(!is_wildcard(u, sort)) {
925 conjuncts.push_back(F::make_binary(var, LEQ, u));
928 conjuncts.push_back(F::make_binary(var, SUBSETEQ, u));
935 if(conjuncts.size() == 0) {
936 return F::make_true();
938 else if(conjuncts.size() == 1) {
939 disjuncts.push_back(std::move(conjuncts[0]));
942 disjuncts.push_back(F::make_nary(AND, std::move(conjuncts)));
945 if(disjuncts.size() == 0) {
946 return F::make_false();
948 else if(disjuncts.size() == 1) {
949 return std::move(disjuncts[0]);
952 return F::make_nary(OR, std::move(disjuncts));
956 F make_solve_item(
const SV& sv) {
961 if(f(sv[1]).is_true()) {
965 return F::make_binary(f(sv[0]), AND, f(sv[1]));
970 void make_seq_search(
const SV& sv, FSeq& seq) {
971 for(
int i = 0; i < sv.size(); ++i) {
972 const auto& sub_search = f(sv[i]);
973 if(sub_search.is(F::Seq) && sub_search.sig() == AND) {
974 for(
int j = 0; j < sub_search.seq().size(); ++j) {
975 seq.push_back(sub_search.seq(j));
979 seq.push_back(sub_search);
984 F make_seq_search(
const SV& sv) {
986 make_seq_search(sv, seq);
987 return F::make_nary(AND, seq);
990 F make_base_search(
const SV& sv) {
992 seq.push_back(F::make_nary(bstring(std::any_cast<std::string>(sv[1]).data()), FSeq{}));
993 seq.push_back(F::make_nary(bstring(std::any_cast<std::string>(sv[2]).data()), FSeq{}));
994 auto array = resolve_array(sv, sv[0]);
995 for(
int i = 0; i < array.seq().size(); ++i) {
996 if(array.seq(i).is_variable()) {
997 seq.push_back(array.seq(i));
1000 return F::make_nary(
"search", seq);
1003 F make_search_annotations(
const SV& sv) {
1004 if(sv.size() == 1) {
1008 return make_seq_search(sv);
1024 template<
class Allocator>
1026 impl::FlatZincParser<Allocator> parser(output);
1027 return parser.parse(input);
1030 template<
class Allocator>
1032 std::ifstream t(filename);
1034 std::string input((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
1038 std::cerr <<
"File `" << filename <<
"` does not exists:." << std::endl;
1043 template<
class Allocator>
1044 battery::shared_ptr<TFormula<Allocator>, Allocator>
parse_flatzinc_str(
const std::string& input,
const Allocator& allocator = Allocator()) {
1049 template<
class Allocator>
1050 battery::shared_ptr<TFormula<Allocator>, Allocator>
parse_flatzinc(
const std::string& filename,
const Allocator& allocator = Allocator()) {