this repo has no description
at develop 30 kB view raw
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 2 3/* 4 * Main authors: 5 * Jip J. Dekker <jip.dekker@monash.edu> 6 */ 7 8/* This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 11 12#include <minizinc/solvers/geas/geas_constraints.hh> 13#include <minizinc/solvers/geas_solverinstance.hh> 14 15namespace MiniZinc { 16GeasSolverInstance::GeasSolverInstance(Env& env, std::ostream& log, 17 SolverInstanceBase::Options* opt) 18 : SolverInstanceImpl<GeasTypes>(env, log, opt), _flat(env.flat()) { 19 registerConstraints(); 20} 21 22void GeasSolverInstance::registerConstraint(const std::string& name, poster p) { 23 _constraintRegistry.add("geas_" + name, p); 24 _constraintRegistry.add(name, p); 25} 26 27void GeasSolverInstance::registerConstraints() { 28 GCLock lock; 29 30 /* Integer Comparison Constraints */ 31 registerConstraint("int_eq", GeasConstraints::p_int_eq); 32 registerConstraint("int_ne", GeasConstraints::p_int_ne); 33 registerConstraint("int_le", GeasConstraints::p_int_le); 34 registerConstraint("int_lt", GeasConstraints::p_int_lt); 35 registerConstraint("int_eq_imp", GeasConstraints::p_int_eq_imp); 36 registerConstraint("int_ne_imp", GeasConstraints::p_int_ne_imp); 37 registerConstraint("int_le_imp", GeasConstraints::p_int_le_imp); 38 registerConstraint("int_lt_imp", GeasConstraints::p_int_lt_imp); 39 registerConstraint("int_eq_reif", GeasConstraints::p_int_eq_reif); 40 registerConstraint("int_ne_reif", GeasConstraints::p_int_ne_reif); 41 registerConstraint("int_le_reif", GeasConstraints::p_int_le_reif); 42 registerConstraint("int_lt_reif", GeasConstraints::p_int_lt_reif); 43 44 /* Integer Arithmetic Constraints */ 45 registerConstraint("int_abs", GeasConstraints::p_int_abs); 46 registerConstraint("int_times", GeasConstraints::p_int_times); 47 registerConstraint("int_div", GeasConstraints::p_int_div); 48 // registerConstraint("int_mod", GeasConstraints::p_int_mod); 49 registerConstraint("int_min", GeasConstraints::p_int_min); 50 registerConstraint("int_max", GeasConstraints::p_int_max); 51 52 /* Integer Linear Constraints */ 53 registerConstraint("int_lin_eq", GeasConstraints::p_int_lin_eq); 54 registerConstraint("int_lin_ne", GeasConstraints::p_int_lin_ne); 55 registerConstraint("int_lin_le", GeasConstraints::p_int_lin_le); 56 registerConstraint("int_lin_eq_imp", GeasConstraints::p_int_lin_eq_imp); 57 registerConstraint("int_lin_ne_imp", GeasConstraints::p_int_lin_ne_imp); 58 registerConstraint("int_lin_le_imp", GeasConstraints::p_int_lin_le_imp); 59 registerConstraint("int_lin_eq_reif", GeasConstraints::p_int_lin_eq_reif); 60 registerConstraint("int_lin_ne_reif", GeasConstraints::p_int_lin_ne_reif); 61 registerConstraint("int_lin_le_reif", GeasConstraints::p_int_lin_le_reif); 62 63 /* Boolean Comparison Constraints */ 64 registerConstraint("bool_eq", GeasConstraints::p_bool_eq); 65 registerConstraint("bool_ne", GeasConstraints::p_bool_ne); 66 registerConstraint("bool_le", GeasConstraints::p_bool_le); 67 registerConstraint("bool_lt", GeasConstraints::p_bool_lt); 68 registerConstraint("bool_eq_imp", GeasConstraints::p_bool_eq_imp); 69 registerConstraint("bool_ne_imp", GeasConstraints::p_bool_ne_imp); 70 registerConstraint("bool_le_imp", GeasConstraints::p_bool_le_imp); 71 registerConstraint("bool_lt_imp", GeasConstraints::p_bool_lt_imp); 72 registerConstraint("bool_eq_reif", GeasConstraints::p_bool_eq_reif); 73 registerConstraint("bool_ne_reif", GeasConstraints::p_bool_ne_reif); 74 registerConstraint("bool_le_reif", GeasConstraints::p_bool_le_reif); 75 registerConstraint("bool_lt_reif", GeasConstraints::p_bool_lt_reif); 76 77 /* Boolean Arithmetic Constraints */ 78 registerConstraint("bool_or", GeasConstraints::p_bool_or); 79 registerConstraint("bool_and", GeasConstraints::p_bool_and); 80 registerConstraint("bool_xor", GeasConstraints::p_bool_xor); 81 registerConstraint("bool_not", GeasConstraints::p_bool_not); 82 registerConstraint("bool_or_imp", GeasConstraints::p_bool_or_imp); 83 registerConstraint("bool_and_imp", GeasConstraints::p_bool_and_imp); 84 registerConstraint("bool_xor_imp", GeasConstraints::p_bool_xor_imp); 85 86 registerConstraint("bool_clause", GeasConstraints::p_bool_clause); 87 registerConstraint("array_bool_or", GeasConstraints::p_array_bool_or); 88 registerConstraint("array_bool_and", GeasConstraints::p_array_bool_and); 89 registerConstraint("bool_clause_imp", GeasConstraints::p_bool_clause_imp); 90 registerConstraint("array_bool_or_imp", GeasConstraints::p_array_bool_or_imp); 91 registerConstraint("array_bool_and_imp", GeasConstraints::p_array_bool_and_imp); 92 registerConstraint("bool_clause_reif", GeasConstraints::p_bool_clause_reif); 93 94 /* Boolean Linear Constraints */ 95 registerConstraint("bool_lin_eq", GeasConstraints::p_bool_lin_eq); 96 registerConstraint("bool_lin_ne", GeasConstraints::p_bool_lin_ne); 97 registerConstraint("bool_lin_le", GeasConstraints::p_bool_lin_le); 98 registerConstraint("bool_lin_eq_imp", GeasConstraints::p_bool_lin_eq_imp); 99 registerConstraint("bool_lin_ne_imp", GeasConstraints::p_bool_lin_ne_imp); 100 registerConstraint("bool_lin_le_imp", GeasConstraints::p_bool_lin_le_imp); 101 registerConstraint("bool_lin_eq_reif", GeasConstraints::p_bool_lin_eq_reif); 102 registerConstraint("bool_lin_ne_reif", GeasConstraints::p_bool_lin_ne_reif); 103 registerConstraint("bool_lin_le_reif", GeasConstraints::p_bool_lin_le_reif); 104 105 /* Coercion Constraints */ 106 registerConstraint("bool2int", GeasConstraints::p_bool2int); 107 108 /* Element Constraints */ 109 registerConstraint("array_int_element", GeasConstraints::p_array_int_element); 110 registerConstraint("array_bool_element", GeasConstraints::p_array_bool_element); 111 registerConstraint("array_var_int_element", GeasConstraints::p_array_var_int_element); 112 registerConstraint("array_var_bool_element", GeasConstraints::p_array_var_bool_element); 113 114 /* Global Constraints */ 115 registerConstraint("all_different_int", GeasConstraints::p_all_different); 116 registerConstraint("alldifferent_except_0", GeasConstraints::p_all_different_except_0); 117 registerConstraint("at_most", GeasConstraints::p_at_most); 118 registerConstraint("at_most1", GeasConstraints::p_at_most1); 119 registerConstraint("cumulative", GeasConstraints::p_cumulative); 120 registerConstraint("cumulative_var", GeasConstraints::p_cumulative); 121 registerConstraint("disjunctive", GeasConstraints::p_disjunctive); 122 registerConstraint("disjunctive_var", GeasConstraints::p_disjunctive); 123 registerConstraint("global_cardinality", GeasConstraints::p_global_cardinality); 124 registerConstraint("table_int", GeasConstraints::p_table_int); 125 126 /**** TODO: NOT YET SUPPORTED: ****/ 127 /* Boolean Arithmetic Constraints */ 128 // registerConstraint("array_bool_xor", GeasConstraints::p_array_bool_xor); 129 // registerConstraint("array_bool_xor_imp", GeasConstraints::p_array_bool_xor_imp); 130 131 /* Floating Point Comparison Constraints */ 132 // registerConstraint("float_eq", GeasConstraints::p_float_eq); 133 // registerConstraint("float_le", GeasConstraints::p_float_le); 134 // registerConstraint("float_lt", GeasConstraints::p_float_lt); 135 // registerConstraint("float_ne", GeasConstraints::p_float_ne); 136 // registerConstraint("float_eq_reif", GeasConstraints::p_float_eq_reif); 137 // registerConstraint("float_le_reif", GeasConstraints::p_float_le_reif); 138 // registerConstraint("float_lt_reif", GeasConstraints::p_float_lt_reif); 139 140 /* Floating Point Arithmetic Constraints */ 141 // registerConstraint("float_abs", GeasConstraints::p_float_abs); 142 // registerConstraint("float_sqrt", GeasConstraints::p_float_sqrt); 143 // registerConstraint("float_times", GeasConstraints::p_float_times); 144 // registerConstraint("float_div", GeasConstraints::p_float_div); 145 // registerConstraint("float_plus", GeasConstraints::p_float_plus); 146 // registerConstraint("float_max", GeasConstraints::p_float_max); 147 // registerConstraint("float_min", GeasConstraints::p_float_min); 148 // registerConstraint("float_acos", GeasConstraints::p_float_acos); 149 // registerConstraint("float_asin", GeasConstraints::p_float_asin); 150 // registerConstraint("float_atan", GeasConstraints::p_float_atan); 151 // registerConstraint("float_cos", GeasConstraints::p_float_cos); 152 // registerConstraint("float_exp", GeasConstraints::p_float_exp); 153 // registerConstraint("float_ln", GeasConstraints::p_float_ln); 154 // registerConstraint("float_log10", GeasConstraints::p_float_log10); 155 // registerConstraint("float_log2", GeasConstraints::p_float_log2); 156 // registerConstraint("float_sin", GeasConstraints::p_float_sin); 157 // registerConstraint("float_tan", GeasConstraints::p_float_tan); 158 159 /* Floating Linear Constraints */ 160 // registerConstraint("float_lin_eq", GeasConstraints::p_float_lin_eq); 161 // registerConstraint("float_lin_eq_reif", GeasConstraints::p_float_lin_eq_reif); 162 // registerConstraint("float_lin_le", GeasConstraints::p_float_lin_le); 163 // registerConstraint("float_lin_le_reif", GeasConstraints::p_float_lin_le_reif); 164 165 /* Coercion Constraints */ 166 // registerConstraint("int2float", GeasConstraints::p_int2float); 167} 168 169void GeasSolverInstance::processFlatZinc() { 170 auto _opt = static_cast<GeasOptions&>(*_options); 171 // Create variables 172 zero = _solver.new_intvar(0, 0); 173 for (auto it = _flat->vardecls().begin(); it != _flat->vardecls().end(); ++it) { 174 if (!it->removed() && it->e()->type().isvar() && it->e()->type().dim() == 0) { 175 VarDecl* vd = it->e(); 176 177 if (vd->type().isbool()) { 178 if (vd->e() == nullptr) { 179 Expression* domain = vd->ti()->domain(); 180 long long int lb; 181 long long int ub; 182 if (domain != nullptr) { 183 IntBounds ib = compute_int_bounds(_env.envi(), domain); 184 lb = ib.l.toInt(); 185 ub = ib.u.toInt(); 186 } else { 187 lb = 0; 188 ub = 1; 189 } 190 if (lb == ub) { 191 geas::patom_t val = (lb == 0) ? geas::at_False : geas::at_True; 192 _variableMap.insert(vd->id(), GeasVariable(val)); 193 } else { 194 auto var = _solver.new_boolvar(); 195 _variableMap.insert(vd->id(), GeasVariable(var)); 196 } 197 } else { 198 Expression* init = vd->e(); 199 if (init->isa<Id>() || init->isa<ArrayAccess>()) { 200 GeasVariable& var = resolveVar(init); 201 assert(var.isBool()); 202 _variableMap.insert(vd->id(), GeasVariable(var.boolVar())); 203 } else { 204 auto b = init->cast<BoolLit>()->v(); 205 geas::patom_t val = b ? geas::at_True : geas::at_False; 206 _variableMap.insert(vd->id(), GeasVariable(val)); 207 } 208 } 209 } else if (vd->type().isfloat()) { 210 if (vd->e() == nullptr) { 211 Expression* domain = vd->ti()->domain(); 212 double lb; 213 double ub; 214 if (domain != nullptr) { 215 FloatBounds fb = compute_float_bounds(_env.envi(), vd->id()); 216 lb = fb.l.toDouble(); 217 ub = fb.u.toDouble(); 218 } else { 219 std::ostringstream ss; 220 ss << "GeasSolverInstance::processFlatZinc: Error: Unbounded variable: " 221 << vd->id()->str(); 222 throw Error(ss.str()); 223 } 224 // TODO: Error correction from double to float?? 225 auto var = _solver.new_floatvar(static_cast<geas::fp::val_t>(lb), 226 static_cast<geas::fp::val_t>(ub)); 227 _variableMap.insert(vd->id(), GeasVariable(var)); 228 } else { 229 Expression* init = vd->e(); 230 if (init->isa<Id>() || init->isa<ArrayAccess>()) { 231 GeasVariable& var = resolveVar(init); 232 assert(var.isFloat()); 233 _variableMap.insert(vd->id(), GeasVariable(var.floatVar())); 234 } else { 235 double fl = init->cast<FloatLit>()->v().toDouble(); 236 auto var = _solver.new_floatvar(static_cast<geas::fp::val_t>(fl), 237 static_cast<geas::fp::val_t>(fl)); 238 _variableMap.insert(vd->id(), GeasVariable(var)); 239 } 240 } 241 } else if (vd->type().isint()) { 242 if (vd->e() == nullptr) { 243 Expression* domain = vd->ti()->domain(); 244 if (domain != nullptr) { 245 IntSetVal* isv = eval_intset(env().envi(), domain); 246 auto var = _solver.new_intvar(static_cast<geas::intvar::val_t>(isv->min().toInt()), 247 static_cast<geas::intvar::val_t>(isv->max().toInt())); 248 if (isv->size() > 1) { 249 vec<int> vals(static_cast<int>(isv->card().toInt())); 250 int i = 0; 251 for (int j = 0; j < isv->size(); ++j) { 252 for (auto k = isv->min(j).toInt(); k <= isv->max(j).toInt(); ++k) { 253 vals[i++] = static_cast<int>(k); 254 } 255 } 256 assert(i == isv->card().toInt()); 257 auto res = geas::make_sparse(var, vals); 258 assert(res); 259 } 260 _variableMap.insert(vd->id(), GeasVariable(var)); 261 } else { 262 std::ostringstream ss; 263 ss << "GeasSolverInstance::processFlatZinc: Error: Unbounded variable: " 264 << vd->id()->str(); 265 throw Error(ss.str()); 266 } 267 } else { 268 Expression* init = vd->e(); 269 if (init->isa<Id>() || init->isa<ArrayAccess>()) { 270 GeasVariable& var = resolveVar(init); 271 assert(var.isInt()); 272 _variableMap.insert(vd->id(), GeasVariable(var.intVar())); 273 } else { 274 auto il = init->cast<IntLit>()->v().toInt(); 275 auto var = _solver.new_intvar(static_cast<geas::intvar::val_t>(il), 276 static_cast<geas::intvar::val_t>(il)); 277 _variableMap.insert(vd->id(), GeasVariable(var)); 278 } 279 } 280 } else { 281 std::stringstream ssm; 282 ssm << "Type " << *vd->ti() << " is currently not supported by Geas."; 283 throw InternalError(ssm.str()); 284 } 285 } 286 } 287 288 // Post constraints 289 for (ConstraintIterator it = _flat->constraints().begin(); it != _flat->constraints().end(); 290 ++it) { 291 if (!it->removed()) { 292 if (auto* c = it->e()->dynamicCast<Call>()) { 293 _constraintRegistry.post(c); 294 } 295 } 296 } 297 // Set objective 298 SolveI* si = _flat->solveItem(); 299 if (si->e() != nullptr) { 300 _objType = si->st(); 301 if (_objType == SolveI::ST_MIN) { 302 _objVar = std::unique_ptr<GeasTypes::Variable>(new GeasTypes::Variable(resolveVar(si->e()))); 303 } else if (_objType == SolveI::ST_MAX) { 304 _objType = SolveI::ST_MIN; 305 _objVar = std::unique_ptr<GeasTypes::Variable>(new GeasTypes::Variable(-asIntVar(si->e()))); 306 } 307 } 308 if (!si->ann().isEmpty()) { 309 std::vector<Expression*> flatAnn; 310 flattenSearchAnnotations(si->ann(), flatAnn); 311 312 for (auto& ann : flatAnn) { 313 if (ann->isa<Call>()) { 314 Call* call = ann->cast<Call>(); 315 if (call->id() == "warm_start") { 316 auto* vars = eval_array_lit(env().envi(), call->arg(0)); 317 auto* vals = eval_array_lit(env().envi(), call->arg(1)); 318 assert(vars->size() == vals->size()); 319 vec<geas::patom_t> ws(static_cast<int>(vars->size())); 320 321 if (vars->type().isIntArray()) { 322 assert(vals->type().isIntArray()); 323 for (int i = 0; i < vars->size(); ++i) { 324 geas::intvar var = asIntVar((*vars)[i]); 325 int val = asInt((*vals)[i]); 326 ws.push(var == val); 327 } 328 } else if (vars->type().isBoolArray()) { 329 assert(vals->type().isBoolArray()); 330 for (int i = 0; i < vars->size(); ++i) { 331 geas::patom_t var = asBoolVar((*vars)[i]); 332 bool val = asBool((*vals)[i]); 333 ws.push(val ? var : ~var); 334 } 335 } else { 336 std::cerr << "WARNING Geas: ignoring warm start annotation of invalid type: " << *ann 337 << std::endl; 338 continue; 339 } 340 _solver.data->branchers.push(geas::warmstart_brancher(ws)); 341 continue; 342 } 343 344 vec<geas::pid_t> pids; 345 geas::VarChoice select = geas::Var_FirstFail; 346 geas::ValChoice choice = geas::Val_Min; 347 if (call->id() == "int_search") { 348 vec<geas::intvar> iv = asIntVar(eval_array_lit(env().envi(), call->arg(0))); 349 pids.growTo(iv.size()); 350 for (int i = 0; i < iv.size(); ++i) { 351 pids[i] = iv[i].p; 352 } 353 } else if (call->id() == "bool_search") { 354 vec<geas::patom_t> bv = asBoolVar(eval_array_lit(env().envi(), call->arg(0))); 355 pids.growTo(bv.size()); 356 for (int i = 0; i < bv.size(); ++i) { 357 pids[i] = bv[i].pid; 358 } 359 } else { 360 std::cerr << "WARNING Geas: ignoring unknown search annotation: " << *ann << std::endl; 361 continue; 362 } 363 ASTString select_str = call->arg(1)->cast<Id>()->str(); 364 if (select_str == "input_order") { 365 select = geas::Var_InputOrder; 366 } else if (select_str == "first_fail") { 367 select = geas::Var_FirstFail; 368 } else if (select_str == "largest") { 369 select = geas::Var_Largest; 370 } else if (select_str == "smallest") { 371 select = geas::Var_Smallest; 372 } else { 373 std::cerr << "WARNING Geas: unknown variable selection '" << select_str 374 << "', using default value First Fail." << std::endl; 375 } 376 ASTString choice_str = call->arg(2)->cast<Id>()->str(); 377 if (choice_str == "indomain_max") { 378 choice = geas::Val_Max; 379 } else if (choice_str == "indomain_min") { 380 choice = geas::Val_Min; 381 } else if (choice_str == "indomain_split") { 382 choice = geas::Val_Split; 383 } else { 384 std::cerr << "WARNING Geas: unknown value selection '" << choice_str 385 << "', using Indomain Min." << std::endl; 386 } 387 388 geas::brancher* b = geas::basic_brancher(select, choice, pids); 389 if (_opt.freeSearch) { 390 vec<geas::brancher*> brv({b, _solver.data->last_branch}); 391 _solver.data->branchers.push(geas::toggle_brancher(brv)); 392 } else { 393 _solver.data->branchers.push(b); 394 } 395 } 396 } 397 } 398} 399 400bool GeasSolverInstance::addSolutionNoGood() { 401 assert(!_varsWithOutput.empty()); 402 geas::model solution = _solver.get_model(); 403 vec<geas::clause_elt> clause; 404 for (auto& var : _varsWithOutput) { 405 if (Expression::dynamicCast<Call>( 406 get_annotation(var->ann(), constants().ann.output_array.aststr())) != nullptr) { 407 if (auto* al = var->e()->dynamicCast<ArrayLit>()) { 408 for (int j = 0; j < al->size(); j++) { 409 if (Id* id = (*al)[j]->dynamicCast<Id>()) { 410 auto geas_var = resolveVar(id); 411 if (geas_var.isBool()) { 412 geas::patom_t bv = geas_var.boolVar(); 413 clause.push(solution.value(bv) ? ~bv : bv); 414 } else if (geas_var.isFloat()) { 415 geas::fp::fpvar fv = geas_var.floatVar(); 416 clause.push(fv < solution[fv]); 417 clause.push(fv > solution[fv]); 418 } else { 419 geas::intvar iv = geas_var.intVar(); 420 clause.push(~(iv == solution[iv])); 421 } 422 } 423 } 424 } 425 } else { 426 auto geas_var = resolveVar(var); 427 if (geas_var.isBool()) { 428 geas::patom_t bv = geas_var.boolVar(); 429 clause.push(solution.value(bv) ? ~bv : bv); 430 } else if (geas_var.isFloat()) { 431 geas::fp::fpvar fv = geas_var.floatVar(); 432 clause.push(fv < solution[fv]); 433 clause.push(fv > solution[fv]); 434 } else { 435 geas::intvar iv = geas_var.intVar(); 436 clause.push(iv != solution[iv]); 437 } 438 } 439 } 440 return geas::add_clause(*_solver.data, clause); 441} 442 443SolverInstanceBase::Status MiniZinc::GeasSolverInstance::solve() { 444 SolverInstanceBase::Status status = SolverInstance::ERROR; 445 auto _opt = static_cast<GeasOptions&>(*_options); 446 auto remaining_time = [_opt] { 447 if (_opt.time == std::chrono::milliseconds(0)) { 448 return 0.0; 449 } 450 using geas_time = std::chrono::duration<double>; 451 static auto timeout = std::chrono::high_resolution_clock::now() + _opt.time; 452 return geas_time(timeout - std::chrono::high_resolution_clock::now()).count(); 453 }; 454 if (_objType == SolveI::ST_SAT) { 455 int nr_solutions = 0; 456 geas::solver::result res = geas::solver::UNKNOWN; 457 while ((_opt.allSolutions || nr_solutions < _opt.nrSolutions) && remaining_time() >= 0.0) { 458 res = _solver.solve({remaining_time(), _opt.conflicts - _solver.data->stats.conflicts}); 459 printSolution(); 460 if (res != geas::solver::SAT) { 461 break; 462 } 463 nr_solutions++; 464 _solver.restart(); 465 if (!addSolutionNoGood()) { 466 res = geas::solver::UNSAT; 467 break; 468 } 469 } 470 switch (res) { 471 case geas::solver::SAT: 472 status = SolverInstance::SAT; 473 break; 474 case geas::solver::UNSAT: 475 if (nr_solutions > 0) { 476 status = SolverInstance::OPT; 477 } else { 478 status = SolverInstance::UNSAT; 479 } 480 break; 481 case geas::solver::UNKNOWN: 482 if (nr_solutions > 0) { 483 status = SolverInstance::SAT; 484 } else { 485 status = SolverInstance::UNKNOWN; 486 } 487 break; 488 default: 489 status = SolverInstance::ERROR; 490 break; 491 } 492 } else { 493 assert(_objType == SolveI::ST_MIN); 494 // TODO: Add float objectives 495 assert(_objVar->isInt()); 496 geas::intvar obj = _objVar->intVar(); 497 geas::solver::result res; 498 while (true) { 499 res = _solver.solve({remaining_time(), _opt.conflicts - _solver.data->stats.conflicts}); 500 geas::intvar::val_t obj_val; 501 if (res != geas::solver::SAT) { 502 break; 503 } 504 status = SolverInstance::SAT; 505 if (_opt.allSolutions) { 506 printSolution(); 507 } 508 obj_val = _solver.get_model()[obj]; 509 510 int step = 1; 511 while (_opt.objProbeLimit > 0) { 512 geas::intvar::val_t assumed_obj; 513 assumed_obj = obj_val - step; 514 assumed_obj = obj.lb(_solver.data) > assumed_obj ? obj.lb(_solver.data) : assumed_obj; 515 if (!_solver.assume(obj == assumed_obj)) { 516 _solver.retract(); 517 break; 518 } 519 res = _solver.solve({remaining_time(), _opt.objProbeLimit}); 520 _solver.retract(); 521 if (res != geas::solver::SAT) { 522 break; 523 } 524 step *= 2; 525 if (_opt.allSolutions) { 526 printSolution(); 527 } 528 obj_val = _solver.get_model()[obj]; 529 } 530 _solver.post(obj < obj_val); 531 } 532 if (status == SolverInstance::ERROR) { 533 switch (res) { 534 case geas::solver::UNSAT: 535 status = SolverInstance::UNSAT; 536 break; 537 case geas::solver::UNKNOWN: 538 status = SolverInstance::UNKNOWN; 539 break; 540 default: 541 assert(false); 542 status = SolverInstance::ERROR; 543 break; 544 } 545 } else { 546 if (res == geas::solver::UNSAT) { 547 status = SolverInstance::OPT; 548 } 549 if (!_opt.allSolutions) { 550 printSolution(); 551 } 552 } 553 } 554 if (_opt.statistics) { 555 printStatistics(); 556 } 557 return status; 558} 559 560Expression* GeasSolverInstance::getSolutionValue(Id* id) { 561 id = id->decl()->id(); 562 if (id->type().isvar()) { 563 GeasVariable& var = resolveVar(id->decl()->id()); 564 geas::model solution = _solver.get_model(); 565 switch (id->type().bt()) { 566 case Type::BT_BOOL: 567 assert(var.isBool()); 568 return constants().boollit(solution.value(var.boolVar())); 569 case Type::BT_FLOAT: 570 assert(var.isFloat()); 571 return FloatLit::a(solution[var.floatVar()]); 572 case Type::BT_INT: 573 assert(var.isInt()); 574 return IntLit::a(solution[var.intVar()]); 575 default: 576 return nullptr; 577 } 578 } else { 579 return id->decl()->e(); 580 } 581} 582 583void GeasSolverInstance::resetSolver() { assert(false); } 584 585GeasTypes::Variable& GeasSolverInstance::resolveVar(Expression* e) { 586 if (auto* id = e->dynamicCast<Id>()) { 587 return _variableMap.get(id->decl()->id()); 588 } 589 if (auto* vd = e->dynamicCast<VarDecl>()) { 590 return _variableMap.get(vd->id()->decl()->id()); 591 } 592 if (auto* aa = e->dynamicCast<ArrayAccess>()) { 593 auto* ad = aa->v()->cast<Id>()->decl(); 594 auto idx = aa->idx()[0]->cast<IntLit>()->v().toInt(); 595 auto* al = eval_array_lit(_env.envi(), ad->e()); 596 return _variableMap.get((*al)[idx]->cast<Id>()); 597 } 598 std::stringstream ssm; 599 ssm << "Expected Id, VarDecl or ArrayAccess instead of \"" << *e << "\""; 600 throw InternalError(ssm.str()); 601} 602 603vec<bool> GeasSolverInstance::asBool(ArrayLit* al) { 604 vec<bool> vec(static_cast<int>(al->size())); 605 for (int i = 0; i < al->size(); ++i) { 606 vec[i] = asBool((*al)[i]); 607 } 608 return vec; 609} 610 611geas::patom_t GeasSolverInstance::asBoolVar(Expression* e) { 612 if (e->type().isvar()) { 613 GeasVariable& var = resolveVar(follow_id_to_decl(e)); 614 assert(var.isBool()); 615 return var.boolVar(); 616 } 617 if (auto* bl = e->dynamicCast<BoolLit>()) { 618 return bl->v() ? geas::at_True : geas::at_False; 619 } 620 std::stringstream ssm; 621 ssm << "Expected bool or int literal instead of: " << *e; 622 throw InternalError(ssm.str()); 623} 624 625vec<geas::patom_t> GeasSolverInstance::asBoolVar(ArrayLit* al) { 626 vec<geas::patom_t> vec(static_cast<int>(al->size())); 627 for (int i = 0; i < al->size(); ++i) { 628 vec[i] = this->asBoolVar((*al)[i]); 629 } 630 return vec; 631} 632 633vec<int> GeasSolverInstance::asInt(ArrayLit* al) { 634 vec<int> vec(static_cast<int>(al->size())); 635 for (int i = 0; i < al->size(); ++i) { 636 vec[i] = this->asInt((*al)[i]); 637 } 638 return vec; 639} 640 641geas::intvar GeasSolverInstance::asIntVar(Expression* e) { 642 if (e->type().isvar()) { 643 GeasVariable& var = resolveVar(follow_id_to_decl(e)); 644 assert(var.isInt()); 645 return var.intVar(); 646 } 647 IntVal i; 648 if (auto* il = e->dynamicCast<IntLit>()) { 649 i = il->v().toInt(); 650 } else if (auto* bl = e->dynamicCast<BoolLit>()) { 651 i = static_cast<long long>(bl->v()); 652 } else { 653 std::stringstream ssm; 654 ssm << "Expected bool or int literal instead of: " << *e; 655 throw InternalError(ssm.str()); 656 } 657 if (i == 0) { 658 return zero; 659 } 660 return _solver.new_intvar(static_cast<geas::intvar::val_t>(i.toInt()), 661 static_cast<geas::intvar::val_t>(i.toInt())); 662} 663 664vec<geas::intvar> GeasSolverInstance::asIntVar(ArrayLit* al) { 665 vec<geas::intvar> vec(static_cast<int>(al->size())); 666 for (int i = 0; i < al->size(); ++i) { 667 vec[i] = this->asIntVar((*al)[i]); 668 } 669 return vec; 670} 671 672void GeasSolverInstance::printStatistics() { 673 auto& st = _solver.data->stats; 674 auto& out = getSolns2Out()->getOutput(); 675 676 out << "%%%mzn-stat: failures=" << st.conflicts << std::endl; // TODO: Statistic name 677 out << "%%%mzn-stat: solveTime=" << st.time << std::endl; 678 out << "%%%mzn-stat: solutions=" << st.solutions << std::endl; 679 out << "%%%mzn-stat: restarts=" << st.restarts << std::endl; 680 out << "%%%mzn-stat: nogoods=" << st.num_learnts << std::endl; // TODO: Statistic name 681 out << "%%%mzn-stat: learntLiterals=" << st.num_learnt_lits << std::endl; // TODO: Statistic name 682} 683 684GeasSolverFactory::GeasSolverFactory() { 685 SolverConfig sc("org.minizinc.geas", getVersion(nullptr)); 686 sc.name("Geas"); 687 sc.mznlib("-Ggeas"); 688 sc.mznlibVersion(1); 689 sc.supportsMzn(false); 690 sc.description(getDescription(nullptr)); 691 sc.tags({ 692 "api", 693 "cp", 694 "float", 695 "int", 696 "lcg", 697 }); 698 sc.stdFlags({"-a", "-f", "-n", "-s", "-t"}); 699 sc.extraFlags({ 700 SolverConfig::ExtraFlag("--conflicts", 701 "Limit the maximum number of conflicts to be used during solving.", 702 SolverConfig::ExtraFlag::FlagType::T_INT, {}, "0"), 703 SolverConfig::ExtraFlag( 704 "--obj-probe", 705 "Number of conflicts to use to probe for better solutions after a new solution is found.", 706 SolverConfig::ExtraFlag::FlagType::T_INT, {}, "0"), 707 }); 708 SolverConfigs::registerBuiltinSolver(sc); 709}; 710 711SolverInstanceBase::Options* GeasSolverFactory::createOptions() { return new GeasOptions; } 712 713SolverInstanceBase* GeasSolverFactory::doCreateSI(Env& env, std::ostream& log, 714 SolverInstanceBase::Options* opt) { 715 return new GeasSolverInstance(env, log, opt); 716} 717 718bool GeasSolverFactory::processOption(SolverInstanceBase::Options* opt, int& i, 719 std::vector<std::string>& argv, 720 const std::string& workingDir) { 721 auto* _opt = static_cast<GeasOptions*>(opt); 722 if (argv[i] == "-a" || argv[i] == "--all-solutions") { 723 _opt->allSolutions = true; 724 } else if (argv[i] == "--conflicts") { 725 if (++i == argv.size()) { 726 return false; 727 } 728 int nodes = atoi(argv[i].c_str()); 729 if (nodes >= 0) { 730 _opt->conflicts = nodes; 731 } 732 } else if (argv[i] == "-f") { 733 _opt->freeSearch = true; 734 } else if (argv[i] == "-n") { 735 if (++i == argv.size()) { 736 return false; 737 } 738 int n = atoi(argv[i].c_str()); 739 if (n >= 0) { 740 _opt->nrSolutions = n; 741 } 742 } else if (argv[i] == "--obj-probe") { 743 if (++i == argv.size()) { 744 return false; 745 } 746 int limit = atoi(argv[i].c_str()); 747 if (limit >= 0) { 748 _opt->objProbeLimit = limit; 749 } 750 } else if (argv[i] == "--solver-statistics" || argv[i] == "-s") { 751 _opt->statistics = true; 752 } else if (argv[i] == "--solver-time-limit" || argv[i] == "-t") { 753 if (++i == argv.size()) { 754 return false; 755 } 756 int time = atoi(argv[i].c_str()); 757 if (time >= 0) { 758 _opt->time = std::chrono::milliseconds(time); 759 } 760 } else { 761 return false; 762 } 763 return true; 764} 765 766void GeasSolverFactory::printHelp(std::ostream& os) { 767 os << "Geas solver plugin options:" << std::endl 768 << " --conflicts <int>" << std::endl 769 << " Limit the maximum number of conflicts to be used during solving." << std::endl 770 << " --obj-probe <int>" << std::endl 771 << " Number of conflicts to use to probe for better solutions after a new solution is " 772 "found." 773 << std::endl 774 << std::endl; 775} 776} // namespace MiniZinc