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(TDIV, sv); }
424 if (name ==
"int_ediv") {
return make_binary_fun_eq(EDIV, sv); }
425 if (name ==
"int_tdiv") {
return make_binary_fun_eq(TDIV, sv); }
426 if (name ==
"int_cdiv") {
return make_binary_fun_eq(CDIV, sv); }
427 if (name ==
"int_fdiv") {
return make_binary_fun_eq(FDIV, sv); }
428 if (name ==
"int_mod") {
return make_binary_fun_eq(EMOD, sv); }
429 if (name ==
"int_plus") {
return make_binary_fun_eq(ADD, sv); }
430 if (name ==
"int_minus") {
return make_binary_fun_eq(SUB, sv); }
431 if (name ==
"int_pow") {
return make_binary_fun_eq(POW, sv); }
432 if (name ==
"int_times") {
return make_binary_fun_eq(MUL, sv); }
433 if (name ==
"int_max") {
return make_binary_fun_eq(MAX, sv); }
434 if (name ==
"int_min") {
return make_binary_fun_eq(MIN, sv); }
435 if (name ==
"int_eq_reif") {
return make_binary_fun_eq(EQ, sv, EQUIV); }
436 if (name ==
"int_le_reif") {
return make_binary_fun_eq(LEQ, sv, EQUIV); }
437 if (name ==
"int_lt_reif") {
return make_binary_fun_eq(LT, sv, EQUIV); }
438 if (name ==
"int_ne_reif") {
return make_binary_fun_eq(NEQ, sv, EQUIV); }
439 if (name ==
"bool2int") {
return make_binary(EQ, sv); }
440 if (name ==
"bool_eq") {
return make_binary(EQ, sv); }
441 if (name ==
"bool_le") {
return make_binary(LEQ, sv); }
442 if (name ==
"bool_lt") {
return make_binary(LT, sv); }
443 if (name ==
"bool_imply") {
return make_binary(IMPLY, sv); }
444 if (name ==
"bool_eq_reif") {
return make_binary_fun_eq(EQ, sv, EQUIV); }
445 if (name ==
"bool_le_reif") {
return make_binary_fun_eq(LEQ, sv, EQUIV); }
446 if (name ==
"bool_lt_reif") {
return make_binary_fun_eq(LT, sv, EQUIV); }
447 if (name ==
"bool_and") {
return make_binary_fun_eq(AND, sv, EQUIV); }
448 if (name ==
"bool_not") {
449 if(sv.size() == 3) {
return make_binary(XOR, sv); }
450 else {
return make_unary_fun(NOT, sv); }
452 if (name ==
"bool_or") {
return make_binary_fun_eq(OR, sv, EQUIV); }
453 if (name ==
"nbool_and") {
return make_nary_fun(AND, sv); }
454 if (name ==
"nbool_or") {
return make_nary_fun(OR, sv); }
455 if (name ==
"nbool_equiv") {
return make_nary_fun(EQUIV, sv); }
456 if (name ==
"bool_xor") {
457 if(sv.size() == 3) {
return make_binary(XOR, sv); }
458 else {
return make_binary_fun_eq(XOR, sv, EQUIV); }
460 if (name ==
"set_card") {
return make_unary_fun_eq(CARD, sv); }
461 if (name ==
"set_diff") {
return make_binary_fun_eq(DIFFERENCE, sv); }
462 if (name ==
"set_eq") {
return make_binary(EQ, sv); }
463 if (name ==
"set_eq_reif") {
return make_binary_fun_eq(EQ, sv, EQUIV); }
464 if (name ==
"set_in") {
return make_binary(IN, sv); }
465 if (name ==
"set_in_reif") {
return make_binary_fun_eq(IN, sv, EQUIV); }
466 if (name ==
"set_intersect") {
return make_binary_fun_eq(INTERSECTION, sv, EQUIV); }
467 if (name ==
"set_union") {
return make_binary_fun_eq(UNION, sv, EQUIV); }
468 if (name ==
"set_ne") {
return make_binary(NEQ, sv); }
469 if (name ==
"set_ne_reif") {
return make_binary_fun_eq(NEQ, sv, EQUIV); }
470 if (name ==
"set_subset") {
return make_binary(SUBSETEQ, sv); }
471 if (name ==
"set_subset_reif") {
return make_binary_fun_eq(SUBSETEQ, sv, EQUIV); }
472 if (name ==
"set_superset") {
return make_binary(SUPSETEQ, sv); }
473 if (name ==
"set_symdiff") {
return make_binary_fun_eq(SYMMETRIC_DIFFERENCE, sv, EQUIV); }
474 if (name ==
"set_le") {
return make_binary(LEQ, sv); }
475 if (name ==
"set_le_reif") {
return make_binary_fun_eq(LEQ, sv, EQUIV); }
476 if (name ==
"set_lt") {
return make_binary(LT, sv); }
477 if (name ==
"set_lt_reif") {
return make_binary_fun_eq(LT, sv, EQUIV); }
478 if (name ==
"float_abs") {
return make_binary_fun_eq(ABS, sv); }
479 if (name ==
"float_neg") {
return make_binary_fun_eq(NEG, sv); }
480 if (name ==
"float_plus") {
return make_binary_fun_eq(ADD, sv); }
481 if (name ==
"float_minus") {
return make_binary_fun_eq(SUB, sv); }
482 if (name ==
"float_times") {
return make_binary_fun_eq(MUL, sv); }
483 if (name ==
"float_acos") {
return make_unary_fun_eq(ACOS, sv); }
484 if (name ==
"float_acosh") {
return make_unary_fun_eq(ACOSH, sv); }
485 if (name ==
"float_asin") {
return make_unary_fun_eq(ASIN, sv); }
486 if (name ==
"float_asinh") {
return make_unary_fun_eq(ASINH, sv); }
487 if (name ==
"float_atan") {
return make_unary_fun_eq(ATAN, sv); }
488 if (name ==
"float_atanh") {
return make_unary_fun_eq(ATANH, sv); }
489 if (name ==
"float_cos") {
return make_unary_fun_eq(COS, sv); }
490 if (name ==
"float_cosh") {
return make_unary_fun_eq(COSH, sv); }
491 if (name ==
"float_sin") {
return make_unary_fun_eq(SIN, sv); }
492 if (name ==
"float_sinh") {
return make_unary_fun_eq(SINH, sv); }
493 if (name ==
"float_tan") {
return make_unary_fun_eq(TAN, sv); }
494 if (name ==
"float_tanh") {
return make_unary_fun_eq(TANH, sv); }
495 if (name ==
"float_div") {
return make_binary(DIV, sv); }
496 if (name ==
"float_eq") {
return make_binary(EQ, sv); }
497 if (name ==
"float_eq_reif") {
return make_binary_fun_eq(EQ, sv, EQUIV); }
498 if (name ==
"float_le") {
return make_binary(LEQ, sv); }
499 if (name ==
"float_le_reif") {
return make_binary_fun_eq(LEQ, sv, EQUIV); }
500 if (name ==
"float_ne") {
return make_binary(NEQ, sv); }
501 if (name ==
"float_ne_reif") {
return make_binary_fun_eq(NEQ, sv, EQUIV); }
502 if (name ==
"float_lt") {
return make_binary(LT, sv); }
503 if (name ==
"float_lt_reif") {
return make_binary_fun_eq(LT, sv, EQUIV); }
504 if (name ==
"float_in") {
return make_float_in(sv); }
505 if (name ==
"float_in_reif") {
506 return F::make_binary(make_float_in(sv), EQUIV, f(sv[4]));
508 if (name ==
"float_log10") {
return make_log_eq(10, sv); }
509 if (name ==
"float_log2") {
return make_log_eq(2, sv); }
510 if (name ==
"float_min") {
return make_binary_fun_eq(MIN, sv); }
511 if (name ==
"float_max") {
return make_binary_fun_eq(MAX, sv); }
512 if (name ==
"float_exp") {
return make_unary_fun_eq(EXP, sv); }
513 if (name ==
"float_ln") {
return make_unary_fun_eq(LN, sv); }
514 if (name ==
"float_pow") {
return make_binary_fun_eq(POW, sv); }
515 if (name ==
"float_sqrt") {
return make_unary_fun_eq(SQRT, sv); }
516 if (name ==
"int2float") {
return make_binary(EQ, sv); }
517 if (name ==
"array_int_element" || name ==
"array_var_int_element"
518 || name ==
"array_bool_element" || name ==
"array_var_bool_element"
519 || name ==
"array_set_element" || name ==
"array_var_set_element"
520 || name ==
"array_float_element" || name ==
"array_var_float_element")
522 return make_element_constraint(name, sv);
524 if (name ==
"int_lin_eq" || name ==
"bool_lin_eq" || name ==
"float_lin_eq" ||
525 name ==
"int_lin_eq_reif" || name ==
"bool_lin_eq_reif" || name ==
"float_lin_eq_reif")
527 return make_linear_constraint(name, EQ, sv);
529 if (name ==
"int_lin_le" || name ==
"bool_lin_le" || name ==
"float_lin_le" ||
530 name ==
"int_lin_le_reif" || name ==
"bool_lin_le_reif" || name ==
"float_lin_le_reif")
532 return make_linear_constraint(name, LEQ, sv);
534 if (name ==
"int_lin_ne" || name ==
"bool_lin_ne" || name ==
"float_lin_ne" ||
535 name ==
"int_lin_ne_reif" || name ==
"bool_lin_ne_reif" || name ==
"float_lin_ne_reif")
537 return make_linear_constraint(name, NEQ, sv);
539 if (name ==
"array_bool_and") {
return make_boolean_constraint(name, AND, sv); }
540 if (name ==
"array_bool_or") {
return make_boolean_constraint(name, OR, sv); }
541 if (name ==
"array_bool_xor") {
return make_boolean_constraint(name, XOR, sv); }
542 if (name ==
"bool_clause" || name ==
"bool_clause_reif") {
543 return make_boolean_clause(name, sv);
545 if(name ==
"turbo_fzn_table_bool" || name ==
"turbo_fzn_table_int") {
546 return make_table_constraint(name, sv, TableKind::PLAIN);
548 if(name ==
"turbo_fzn_short_table_int" || name ==
"turbo_fzn_short_table_set_of_int") {
549 return make_table_constraint(name, sv, TableKind::SHORT);
551 if(name ==
"turbo_fzn_basic_table_int" || name ==
"turbo_fzn_basic_table_set_of_int") {
552 return make_table_constraint(name, sv, TableKind::BASIC);
554 if(name ==
"turbo_fzn_compressed_table_int") {
555 return make_table_constraint(name, sv, TableKind::COMPRESSED);
557 return make_error(sv,
"Unknown predicate `" + name +
"`");
560 F function_call(
const SV &sv) {
561 auto name = std::any_cast<std::string>(sv[0]);
565 auto p = predicate_call(sv);
572 if(name ==
"int_abs") {
return make_unary_fun(ABS, sv); }
573 if (name ==
"int_neg") {
return make_unary_fun(NEG, sv); }
574 if (name ==
"int_div") {
return make_binary_fun(TDIV, sv); }
575 if (name ==
"int_ediv") {
return make_binary_fun(EDIV, sv); }
576 if (name ==
"int_fdiv") {
return make_binary_fun(FDIV, sv); }
577 if (name ==
"int_cdiv") {
return make_binary_fun(CDIV, sv); }
578 if (name ==
"int_tdiv") {
return make_binary_fun(TDIV, sv); }
579 if (name ==
"int_mod") {
return make_binary_fun(EMOD, sv); }
580 if (name ==
"int_plus") {
return make_binary_fun(ADD, sv); }
581 if (name ==
"int_minus") {
return make_binary_fun(SUB, sv); }
582 if (name ==
"int_pow") {
return make_binary_fun(POW, sv); }
583 if (name ==
"int_times") {
return make_binary_fun(MUL, sv); }
584 if (name ==
"int_max") {
return make_binary_fun(MAX, sv); }
585 if (name ==
"int_min") {
return make_binary_fun(MIN, sv); }
586 if (name ==
"bool_and") {
return make_binary_fun(AND, sv); }
587 if (name ==
"bool_not") {
return make_unary_fun(NOT, sv); }
588 if (name ==
"bool_or") {
return make_binary_fun(OR, sv); }
589 if (name ==
"bool_xor") {
return make_binary_fun(XOR, sv); }
590 if (name ==
"set_card") {
return make_unary_fun(CARD, sv); }
591 if (name ==
"set_diff") {
return make_binary_fun(DIFFERENCE, sv); }
592 if (name ==
"set_intersect") {
return make_binary_fun(INTERSECTION, sv); }
593 if (name ==
"set_union") {
return make_binary_fun(UNION, sv); }
594 if (name ==
"set_symdiff") {
return make_binary_fun(SYMMETRIC_DIFFERENCE, sv); }
595 if (name ==
"float_abs") {
return make_binary_fun(ABS, sv); }
596 if (name ==
"float_neg") {
return make_binary_fun(NEG, sv); }
597 if (name ==
"float_plus") {
return make_binary_fun(ADD, sv); }
598 if (name ==
"float_minus") {
return make_binary_fun(SUB, sv); }
599 if (name ==
"float_times") {
return make_binary_fun(MUL, sv); }
600 if (name ==
"float_acos") {
return make_unary_fun(ACOS, sv); }
601 if (name ==
"float_acosh") {
return make_unary_fun(ACOSH, sv); }
602 if (name ==
"float_asin") {
return make_unary_fun(ASIN, sv); }
603 if (name ==
"float_asinh") {
return make_unary_fun(ASINH, sv); }
604 if (name ==
"float_atan") {
return make_unary_fun(ATAN, sv); }
605 if (name ==
"float_atanh") {
return make_unary_fun(ATANH, sv); }
606 if (name ==
"float_cos") {
return make_unary_fun(COS, sv); }
607 if (name ==
"float_cosh") {
return make_unary_fun(COSH, sv); }
608 if (name ==
"float_sin") {
return make_unary_fun(SIN, sv); }
609 if (name ==
"float_sinh") {
return make_unary_fun(SINH, sv); }
610 if (name ==
"float_tan") {
return make_unary_fun(TAN, sv); }
611 if (name ==
"float_tanh") {
return make_unary_fun(TANH, sv); }
612 if (name ==
"float_div") {
return make_binary_fun(DIV, sv); }
613 if (name ==
"float_log10") {
return make_log(10, sv); }
614 if (name ==
"float_log2") {
return make_log(2, sv); }
615 if (name ==
"float_min") {
return make_binary_fun(MIN, sv); }
616 if (name ==
"float_max") {
return make_binary_fun(MAX, sv); }
617 if (name ==
"float_exp") {
return make_unary_fun(EXP, sv); }
618 if (name ==
"float_ln") {
return make_unary_fun(LN, sv); }
619 if (name ==
"float_pow") {
return make_binary_fun(POW, sv); }
620 if (name ==
"float_sqrt") {
return make_unary_fun(SQRT, sv); }
621 return make_error(sv,
"Unknown function or predicate symbol `" + name +
"`");
625 F make_statements(
const SV& sv) {
631 for(
int i = 0; i < sv.size(); ++i) {
632 F formula = f(sv[i]);
633 if(!formula.is_true()) {
634 children.push_back(formula);
637 return F::make_nary(AND, std::move(children));
641 F make_existential(
const SV& sv,
const So& ty,
const std::string& name,
const std::any& sv_annots) {
642 auto f = F::make_exists(UNTYPED,
643 LVar<allocator_type>(name.data()),
645 auto annots = std::any_cast<SV>(sv_annots);
646 return update_with_annotations(sv, f, annots);
650 std::string make_array_access(
const S& name,
int i) {
651 return std::string(name.data()) +
"[" + std::to_string(i+1) +
"]";
654 F make_variable_init_decl(
const SV& sv) {
655 auto name = std::any_cast<std::string>(sv[1]);
656 auto var_decl = make_variable_decl(sv, name, sv[0], sv[2]);
658 return F::make_binary(std::move(var_decl), AND,
660 F::make_lvar(UNTYPED, LVar<allocator_type>(name.data())),
665 return std::move(var_decl);
669 F make_variable_decl(
const SV& sv,
const std::string& name,
const std::any& typeVar,
const std::any& annots) {
671 auto ty = std::any_cast<So>(typeVar);
672 return make_existential(sv, ty, name, annots);
674 catch(std::bad_any_cast) {
675 auto typeValue = f(typeVar);
676 auto inConstraint = F::make_binary(F::make_lvar(UNTYPED, LVar<allocator_type>(name.data())), IN, typeValue);
677 auto sort = typeValue.sort();
678 if(!sort.has_value() || !sort->is_set()) {
679 return make_error(sv,
"We only allow type-value of variables to be of type Set.");
681 auto exists = make_existential(sv, *(sort->sub), name, annots);
682 return F::make_binary(std::move(exists), AND, std::move(inConstraint));
686 F make_element_constraint(
const std::string& name,
const SV& sv) {
688 return make_error(sv,
"`" + name +
"` expects 3 parameters, but we got `" + std::to_string(sv.size()-1) +
"` parameters");
690 auto index = f(sv[1]);
691 auto array = resolve_array(sv, sv[2]);
692 if(!array.is(F::Seq)) {
695 auto value = f(sv[3]);
697 for(
int i = 0; i < array.seq().size(); ++i) {
699 seq.push_back(F::make_binary(
700 F::make_binary(index, EQ, F::make_z(i+1)),
702 F::make_binary(array.seq(i), EQ, value)));
704 return F::make_nary(AND, std::move(seq));
707 F resolve_bool(
const SV& sv,
const std::any& any) {
709 auto boolParam = f(any);
710 if(boolParam.is(F::LV)) {
711 std::string paramName(boolParam.lv().data());
712 if(params.contains(paramName)) {
713 boolParam = params[paramName];
716 return make_error(sv,
"Undeclared parameter `" + paramName +
"`.");
719 if(boolParam.is(F::B)) {
723 return make_error(sv,
"Expects a Boolean parameter.");
726 catch(std::bad_any_cast) {
727 return make_error(sv,
"Expects a Boolean parameter.");
733 F resolve_array(
const SV& sv,
const std::any& any) {
736 auto arrayVar = f(any);
737 if(arrayVar.is(F::LV)) {
738 std::string arrayName(arrayVar.lv().data());
739 if(arrays.contains(arrayName)) {
740 int size = arrays[arrayName];
741 for(
int i = 0; i < size; ++i) {
742 auto varName = make_array_access(arrayName, i);
743 if(params.contains(varName)) {
744 seq.push_back(params[varName]);
747 seq.push_back(F::make_lvar(UNTYPED, LVar<allocator_type>(varName.data())));
752 return make_error(sv,
"Unknown array parameter `" + arrayName +
"`");
756 return make_error(sv,
"Expects an array or the name of an array.");
759 catch(std::bad_any_cast) {
761 auto array = std::any_cast<SV>(any);
762 for(
int i = 0; i < array.size(); ++i) {
763 seq.push_back(f(array[i]));
766 catch(std::bad_any_cast) {
767 return make_error(sv,
"Expects an array of valid elements.");
770 return F::make_nary(AND, std::move(seq));
773 F make_linear_constraint(
const std::string& name, Sig sig,
const SV& sv) {
774 if(sv.size() != 4 && sv.size() != 5) {
775 return make_error(sv,
"`" + name +
"` expects 3 (or 4 if reified) parameters, but we got `" + std::to_string(sv.size() - 1) +
"` parameters");
777 auto as = resolve_array(sv, sv[1]);
778 if(!as.is(F::Seq)) {
return as; }
779 auto bs = resolve_array(sv, sv[2]);
780 if(!bs.is(F::Seq)) {
return bs; }
782 if(as.seq().size() != bs.seq().size()) {
783 return make_error(sv,
"`" + name +
"` expects arrays of the same size.");
786 for(
int i = 0; i < as.seq().size(); ++i) {
787 sum.push_back(F::make_binary(as.seq(i), MUL, bs.seq(i)));
791 ? F::make_binary(std::move(sum[0]), sig, c)
792 : F::make_binary(F::make_nary(ADD, std::move(sum)), sig, c);
794 return F::make_binary(f(sv[4]), EQUIV, std::move(linearCons));
797 return std::move(linearCons);
801 F make_boolean_constraint(
const std::string& name, Sig sig,
const SV& sv) {
802 if(sv.size() != 2 && sv.size() != 3) {
803 return make_error(sv,
"`" + name +
"` expects 1 (or 2 if reified) parameters, but we got `" + std::to_string(sv.size() - 1) +
"` parameters");
805 auto array = resolve_array(sv, sv[1]);
806 if(!array.is(F::Seq)) {
return array; }
808 return F::make_binary(f(sv[2]), EQUIV, F::make_nary(sig, array.seq()));
811 return F::make_nary(sig, array.seq());
815 F make_boolean_clause(
const std::string& name,
const SV& sv) {
816 if(sv.size() != 3 && sv.size() != 4) {
817 return make_error(sv,
"`" + name +
"` expects 2 (or 3 if reified) parameters, but we got `" + std::to_string(sv.size() - 1) +
"` parameters");
819 auto as = resolve_array(sv, sv[1]);
820 if(!as.is(F::Seq)) {
return as; }
821 auto bs = resolve_array(sv, sv[2]);
822 if(!bs.is(F::Seq)) {
return bs; }
824 for(
int i = 0; i < bs.seq().size(); ++i) {
825 negs.push_back(F::make_unary(NOT, bs.seq(i)));
827 F clause = F::make_binary(F::make_nary(OR, as.seq()), OR, F::make_nary(OR, negs));
829 return F::make_binary(f(sv[3]), EQUIV, std::move(clause));
832 return std::move(clause);
840 bool is_wildcard(
const F& f, So sort) {
842 return (f.is(F::Z) && f.z() == 2147483647)
843 || (f.is(F::S) && f.s().size() == 0);
845 else if(sort.is_set() && f.is(F::S) && f.s().size() == 1) {
846 auto l = battery::get<0>(f.s()[0]);
847 auto u = battery::get<1>(f.s()[0]);
848 return l.is(F::Z) && u.is(F::Z) && l.z() == 2147483647 && u.z() == 2147483647;
853 So sort_of_table_constraint(
const std::string& name) {
854 if(name ==
"turbo_fzn_table_bool") {
return So(So::Bool); }
855 else if(name ==
"turbo_fzn_table_int") {
return So(So::Int); }
856 else if(name ==
"turbo_fzn_short_table_int") {
return So(So::Int); }
857 else if(name ==
"turbo_fzn_short_table_set_of_int") {
return So(So::Set, So(So::Int)); }
858 else if(name ==
"turbo_fzn_basic_table_int") {
return So(So::Int); }
859 else if(name ==
"turbo_fzn_basic_table_set_of_int") {
return So(So::Set, So(So::Int)); }
860 else if(name ==
"turbo_fzn_compressed_table_int") {
return So(So::Int); }
861 else { printf(
"missing table constraint."); assert(
false);
return So(So::Bool); }
864 F make_table_constraint(
const std::string& name,
const SV& sv, TableKind kind) {
865 bool positive =
true;
868 if(sv.size() != 3 && (name ==
"turbo_fzn_table_bool" || name ==
"turbo_fzn_table_bool")) {
869 return make_error(sv,
"`" + name +
"` expects 2 parameters, but we got `" + std::to_string(sv.size() - 1) +
"` parameters");
873 return make_error(sv,
"`" + name +
"` expects 3 parameters, but we got `" + std::to_string(sv.size() - 1) +
"` parameters");
875 auto boolParam = resolve_bool(sv, sv[1]);
876 if(!boolParam.is(F::B)) {
return boolParam; }
877 positive = boolParam.b();
881 auto header = resolve_array(sv, sv[header_idx]);
882 if(!header.is(F::Seq)) {
return header; }
883 auto table = resolve_array(sv, sv[table_idx]);
884 if(!table.is(F::Seq)) {
return table; }
885 size_t num_t_cols = (kind == TableKind::BASIC) ? header.seq().size() * 2 : header.seq().size();
886 if(table.seq().size() % num_t_cols != 0) {
887 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).");
889 size_t num_cols = header.seq().size();
890 size_t num_rows = table.seq().size() / header.seq().size();
891 So sort = sort_of_table_constraint(name);
893 for(
int i = 0; i < num_rows; ++i) {
895 for(
int z = 0; z < num_cols; ++z) {
896 int j = z * (kind == TableKind::BASIC ? 2 : 1);
897 auto cell = table.seq(i*num_t_cols + j);
898 auto var = header.seq(z);
900 case TableKind::SHORT: {
901 if(is_wildcard(cell, sort)) {
continue; }
903 case TableKind::PLAIN: {
904 if(!cell.is(F::S) && !cell.is(F::Z) && !cell.is(F::B)) {
905 return make_error(sv,
"`" + name +
"` expects each cell to be an integer, a set or a Boolean.");
907 conjuncts.push_back(F::make_binary(var, EQ, cell));
910 case TableKind::COMPRESSED: {
912 return make_error(sv,
"`" + name +
"` expects each cell to be a set.");
914 if(is_wildcard(cell, sort)) {
continue; }
915 conjuncts.push_back(F::make_binary(var, IN, cell));
918 case TableKind::BASIC: {
920 auto u = table.seq(i*num_t_cols + j + 1);
921 if(!l.is(F::S) && !l.is(F::Z) && !u.is(F::S) && !u.is(F::Z)) {
922 return make_error(sv,
"`" + name +
"` expects each cell to be an integer or a set.");
924 if(!is_wildcard(l, sort)) {
926 conjuncts.push_back(F::make_binary(var, GEQ, l));
929 conjuncts.push_back(F::make_binary(var, SUPSETEQ, l));
932 if(!is_wildcard(u, sort)) {
934 conjuncts.push_back(F::make_binary(var, LEQ, u));
937 conjuncts.push_back(F::make_binary(var, SUBSETEQ, u));
944 if(conjuncts.size() == 0) {
945 return F::make_true();
947 else if(conjuncts.size() == 1) {
948 disjuncts.push_back(std::move(conjuncts[0]));
951 disjuncts.push_back(F::make_nary(AND, std::move(conjuncts)));
954 if(disjuncts.size() == 0) {
955 return F::make_false();
957 else if(disjuncts.size() == 1) {
958 return std::move(disjuncts[0]);
961 return F::make_nary(OR, std::move(disjuncts));
965 F make_solve_item(
const SV& sv) {
970 if(f(sv[1]).is_true()) {
974 return F::make_binary(f(sv[0]), AND, f(sv[1]));
979 void make_seq_search(
const SV& sv, FSeq& seq) {
980 for(
int i = 0; i < sv.size(); ++i) {
981 const auto& sub_search = f(sv[i]);
982 if(sub_search.is(F::Seq) && sub_search.sig() == AND) {
983 for(
int j = 0; j < sub_search.seq().size(); ++j) {
984 seq.push_back(sub_search.seq(j));
988 seq.push_back(sub_search);
993 F make_seq_search(
const SV& sv) {
995 make_seq_search(sv, seq);
996 return F::make_nary(AND, seq);
999 F make_base_search(
const SV& sv) {
1001 seq.push_back(F::make_nary(bstring(std::any_cast<std::string>(sv[1]).data()), FSeq{}));
1002 seq.push_back(F::make_nary(bstring(std::any_cast<std::string>(sv[2]).data()), FSeq{}));
1003 auto array = resolve_array(sv, sv[0]);
1004 for(
int i = 0; i < array.seq().size(); ++i) {
1005 if(array.seq(i).is_variable()) {
1006 seq.push_back(array.seq(i));
1009 return F::make_nary(
"search", seq);
1012 F make_search_annotations(
const SV& sv) {
1013 if(sv.size() == 1) {
1017 return make_seq_search(sv);
1033 template<
class Allocator>
1035 impl::FlatZincParser<Allocator> parser(output);
1036 return parser.parse(input);
1039 template<
class Allocator>
1041 std::ifstream t(filename);
1043 std::string input((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
1044 return parse_flatzinc_str<Allocator>(input, output);
1047 std::cerr <<
"File `" << filename <<
"` does not exists:." << std::endl;
1052 template<
class Allocator>
1053 battery::shared_ptr<TFormula<Allocator>, Allocator>
parse_flatzinc_str(
const std::string& input,
const Allocator& allocator = Allocator()) {
1058 template<
class Allocator>
1059 battery::shared_ptr<TFormula<Allocator>, Allocator>
parse_flatzinc(
const std::string& filename,
const Allocator& allocator = Allocator()) {