this repo has no description
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 2/* 3 * Main authors: 4 * Christian Schulte <schulte@gecode.org> 5 * 6 * Copyright: 7 * Christian Schulte, 2004 8 * 9 * This file is part of Gecode, the generic constraint 10 * development environment: 11 * http://www.gecode.org 12 * 13 * 14 * Permission is hereby granted, free of charge, to any person obtaining 15 * a copy of this software and associated documentation files (the 16 * "Software"), to deal in the Software without restriction, including 17 * without limitation the rights to use, copy, modify, merge, publish, 18 * distribute, sublicense, and/or sell copies of the Software, and to 19 * permit persons to whom the Software is furnished to do so, subject to 20 * the following conditions: 21 * 22 * The above copyright notice and this permission notice shall be 23 * included in all copies or substantial portions of the Software. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 * 33 */ 34 35#include <gecode/driver.hh> 36 37#include <iostream> 38#include <iomanip> 39 40#include <cstdlib> 41#include <cstring> 42 43namespace Gecode { 44 45 namespace Driver { 46 47 /* 48 * Option baseclass 49 * 50 */ 51 char* 52 BaseOption::strdup(const char* s) { 53 if (s == nullptr) 54 return nullptr; 55 size_t l = strlen(s) + 1; 56 char* d = static_cast<char*>(heap.ralloc(l)); 57 (void) memcpy(d,s,l); 58 return d; 59 } 60 61 char* 62 BaseOption::stredup(const char* s) { 63 if (s == nullptr) 64 return nullptr; 65 size_t l = strlen(s) + 1; 66 char* d = static_cast<char*>(heap.ralloc(l+1)); 67 d[0] = '-'; 68 (void) memcpy(d+1,s,l); 69 return d; 70 } 71 72 void 73 BaseOption::strdel(const char* s) { 74 if (s == nullptr) 75 return; 76 heap.rfree(const_cast<char*>(s)); 77 } 78 79 char* 80 BaseOption::argument(int argc, char* argv[]) const { 81 if (argc < 2) 82 return nullptr; 83 const char* s = argv[1]; 84 if (s[0] == '-') { 85 s++; 86 if (s[0] == '-') 87 s++; 88 } else { 89 return nullptr; 90 } 91 if (strcmp(s,eopt)) 92 return nullptr; 93 if (argc == 2) { 94 std::cerr << "Missing argument for option \"" << iopt << "\"" 95 << std::endl; 96 exit(EXIT_FAILURE); 97 } 98 return argv[2]; 99 } 100 101 BaseOption::BaseOption(const char* o, const char* e) 102 : eopt(strdup(o)), iopt(stredup(o)), exp(strdup(e)) {} 103 104 BaseOption::~BaseOption(void) { 105 strdel(eopt); 106 strdel(iopt); 107 strdel(exp); 108 } 109 110 111 StringValueOption::StringValueOption(const char* o, const char* e, 112 const char* v) 113 : BaseOption(o,e), cur(strdup(v)) {} 114 void 115 StringValueOption::value(const char* v) { 116 strdel(cur); 117 cur = strdup(v); 118 } 119 int 120 StringValueOption::parse(int argc, char* argv[]) { 121 if (char* a = argument(argc,argv)) { 122 cur = strdup(a); 123 return 2; 124 } 125 return 0; 126 } 127 void 128 StringValueOption::help(void) { 129 std::cerr << '\t' << iopt << " (string) default: " 130 << ((cur == nullptr) ? "NONE" : cur) << std::endl 131 << "\t\t" << exp << std::endl; 132 } 133 StringValueOption::~StringValueOption(void) { 134 strdel(cur); 135 } 136 137 138 139 void 140 StringOption::add(int v, const char* o, const char* h) { 141 Value* n = new Value; 142 n->val = v; 143 n->opt = strdup(o); 144 n->help = strdup(h); 145 n->next = nullptr; 146 if (fst == nullptr) { 147 fst = n; 148 } else { 149 lst->next = n; 150 } 151 lst = n; 152 } 153 int 154 StringOption::parse(int argc, char* argv[]) { 155 if (char* a = argument(argc,argv)) { 156 for (Value* v = fst; v != nullptr; v = v->next) 157 if (!strcmp(a,v->opt)) { 158 cur = v->val; 159 return 2; 160 } 161 std::cerr << "Wrong argument \"" << a 162 << "\" for option \"" << iopt << "\"" 163 << std::endl; 164 exit(EXIT_FAILURE); 165 } 166 return 0; 167 } 168 void 169 StringOption::help(void) { 170 if (fst == nullptr) 171 return; 172 std::cerr << '\t' << iopt << " ("; 173 const char* d = nullptr; 174 for (Value* v = fst; v != nullptr; v = v->next) { 175 std::cerr << v->opt << ((v->next != nullptr) ? ", " : ""); 176 if (v->val == cur) 177 d = v->opt; 178 } 179 std::cerr << ")"; 180 if (d != nullptr) 181 std::cerr << " default: " << d; 182 std::cerr << std::endl << "\t\t" << exp << std::endl; 183 for (Value* v = fst; v != nullptr; v = v->next) 184 if (v->help != nullptr) 185 std::cerr << "\t\t " << v->opt << ": " << v->help << std::endl; 186 } 187 188 StringOption::~StringOption(void) { 189 Value* v = fst; 190 while (v != nullptr) { 191 strdel(v->opt); 192 strdel(v->help); 193 Value* n = v->next; 194 delete v; 195 v = n; 196 } 197 } 198 199 200 int 201 IntOption::parse(int argc, char* argv[]) { 202 if (char* a = argument(argc,argv)) { 203 cur = atoi(a); 204 return 2; 205 } 206 return 0; 207 } 208 209 void 210 IntOption::help(void) { 211 std::cerr << '\t' << iopt << " (int) default: " << cur << std::endl 212 << "\t\t" << exp << std::endl; 213 } 214 215 216 int 217 UnsignedIntOption::parse(int argc, char* argv[]) { 218 if (char* a = argument(argc,argv)) { 219 cur = static_cast<unsigned int>(atoi(a)); 220 return 2; 221 } 222 return 0; 223 } 224 225 void 226 UnsignedIntOption::help(void) { 227 std::cerr << '\t' << iopt << " (unsigned int) default: " 228 << cur << std::endl 229 << "\t\t" << exp << std::endl; 230 } 231 232 233 int 234 UnsignedLongLongIntOption::parse(int argc, char* argv[]) { 235 if (char* a = argument(argc,argv)) { 236 cur = static_cast<unsigned int>(atoll(a)); 237 return 2; 238 } 239 return 0; 240 } 241 242 void 243 UnsignedLongLongIntOption::help(void) { 244 std::cerr << '\t' << iopt << " (unsigned long long int) default: " 245 << cur << std::endl 246 << "\t\t" << exp << std::endl; 247 } 248 249 250 int 251 DoubleOption::parse(int argc, char* argv[]) { 252 if (char* a = argument(argc,argv)) { 253 cur = atof(a); 254 return 2; 255 } 256 return 0; 257 } 258 259 void 260 DoubleOption::help(void) { 261 using namespace std; 262 cerr << '\t' << iopt << " (double) default: " << cur << endl 263 << "\t\t" << exp << endl; 264 } 265 266 267 int 268 BoolOption::parse(int argc, char* argv[]) { 269 if (argc < 2) 270 return 0; 271 const char* s = argv[1]; 272 if (s[0] == '-') { 273 s++; 274 if (s[0] == '-') 275 s++; 276 } else { 277 return 0; 278 } 279 if (strcmp(s,eopt)) 280 return 0; 281 if (argc == 2) { 282 // Option without argument 283 cur = true; 284 return 1; 285 } else if (!strcmp(argv[2],"true") || !strcmp(argv[2],"1")) { 286 cur = true; 287 return 2; 288 } else if (!strcmp(argv[2],"false") || !strcmp(argv[2],"0")) { 289 cur = false; 290 return 2; 291 } else { 292 // Option without argument 293 cur = true; 294 return 1; 295 } 296 return 0; 297 } 298 299 void 300 BoolOption::help(void) { 301 using namespace std; 302 cerr << '\t' << iopt << " (optional: false, 0, true, 1) default: " 303 << (cur ? "true" : "false") << endl 304 << "\t\t" << exp << endl; 305 } 306 307 /* 308 * Integer propagation level option 309 * 310 */ 311 IplOption::IplOption(IntPropLevel ipl) 312 : BaseOption("ipl","integer propagation level (comma-separated list)"), 313 cur(ipl) {} 314 315 int 316 IplOption::parse(int argc, char* argv[]) { 317 if (char* a = argument(argc,argv)) { 318 int b = IPL_DEF; 319 int m = IPL_DEF; 320 do { 321 // Search for a comma 322 char* c = a; 323 while ((*c != ',') && (*c != 0)) 324 c++; 325 unsigned int e = static_cast<unsigned int>(c-a); 326 if (!strncmp("def",a,e)) { b = IPL_DEF; } 327 else if (!strncmp("val",a,e)) { b = IPL_VAL; } 328 else if (!strncmp("bnd",a,e)) { b = IPL_BND; } 329 else if (!strncmp("dom",a,e)) { b = IPL_DOM; } 330 else if (!strncmp("basic",a,e)) { m |= IPL_BASIC; } 331 else if (!strncmp("advanced",a,e)) { m |= IPL_ADVANCED; } 332 else { 333 std::cerr << "Wrong argument \"" << a 334 << "\" for option \"" << iopt << "\"" 335 << std::endl; 336 exit(EXIT_FAILURE); 337 } 338 339 if (*c == ',') a = c+1; else a = c; 340 341 } while (*a != 0); 342 343 cur = static_cast<IntPropLevel>(b | m); 344 return 2; 345 } 346 return 0; 347 } 348 349 void 350 IplOption::help(void) { 351 using namespace std; 352 cerr << '\t' << iopt 353 << " (def,val,bnd,dom,basic,advanced)" << endl 354 << "\t\tdefault: "; 355 switch (vbd(cur)) { 356 case IPL_DEF: cerr << "def"; break; 357 case IPL_VAL: cerr << "val"; break; 358 case IPL_BND: cerr << "bnd"; break; 359 case IPL_DOM: cerr << "dom"; break; 360 default: GECODE_NEVER; 361 } 362 if (cur & IPL_BASIC) cerr << ",basic"; 363 if (cur & IPL_ADVANCED) cerr << ",advanced"; 364 cerr << endl << "\t\t" << exp << endl; 365 } 366 367 368 /* 369 * Trace flag option 370 * 371 */ 372 TraceOption::TraceOption(int f) 373 : BaseOption("trace","trace flags (comma-separated list)"), 374 cur(f) {} 375 376 int 377 TraceOption::parse(int argc, char* argv[]) { 378 if (char* a = argument(argc,argv)) { 379 cur = 0; 380 do { 381 // Search for a comma 382 char* c = a; 383 while ((*c != ',') && (*c != 0)) 384 c++; 385 unsigned int e = static_cast<unsigned int>(c-a); 386 if (!strncmp("init",a,e)) { cur |= TE_INIT; } 387 else if (!strncmp("prune",a,e)) { cur |= TE_PRUNE; } 388 else if (!strncmp("fix",a,e)) { cur |= TE_FIX; } 389 else if (!strncmp("fail",a,e)) { cur |= TE_FAIL; } 390 else if (!strncmp("done",a,e)) { cur |= TE_DONE ; } 391 else if (!strncmp("propagate",a,e)) { cur |= TE_PROPAGATE; } 392 else if (!strncmp("commit",a,e)) { cur |= TE_COMMIT; } 393 else if (!strncmp("post",a,e)) { cur |= TE_POST; } 394 else if (!strncmp("none",a,e) || 395 !strncmp("false",a,e) || 396 !strncmp("0",a,e)) { cur = 0; } 397 else if (!strncmp("all",a,e) || 398 !strncmp("1",a,e)) { cur = (TE_INIT | 399 TE_PRUNE | 400 TE_FIX | 401 TE_FAIL | 402 TE_DONE | 403 TE_PROPAGATE | 404 TE_COMMIT | 405 TE_POST); } 406 else if (!strncmp("variable",a,e)) { cur = (TE_INIT | 407 TE_PRUNE | 408 TE_FIX | 409 TE_FAIL | 410 TE_DONE); } 411 else if (!strncmp("general",a,e)) { cur = (TE_PROPAGATE | 412 TE_COMMIT | 413 TE_POST); } 414 else { 415 std::cerr << "Wrong argument \"" << a 416 << "\" for option \"" << iopt << "\"" 417 << std::endl; 418 exit(EXIT_FAILURE); 419 } 420 421 if (*c == ',') a = c+1; else a = c; 422 423 } while (*a != 0); 424 425 return 2; 426 } 427 return 0; 428 } 429 430 void 431 TraceOption::help(void) { 432 using namespace std; 433 cerr << '\t' << iopt 434 << " (init,prune,fix,fail,done,propagate,commit,post,none,all,variable,general)" 435 << " default: "; 436 if (cur == 0) { 437 cerr << "none"; 438 } else if (cur == (TE_INIT | TE_PRUNE | TE_FIX | TE_FAIL | TE_DONE | 439 TE_PROPAGATE | TE_COMMIT | TE_POST)) { 440 cerr << "all"; 441 } else if (cur == (TE_INIT | TE_PRUNE | TE_FIX | TE_FAIL | TE_DONE)) { 442 cerr << "variable"; 443 } else if (cur == (TE_PROPAGATE | TE_COMMIT | TE_POST)) { 444 cerr << "general"; 445 } else { 446 int f = cur; 447 if ((f & TE_INIT) != 0) { 448 cerr << "init"; 449 f -= TE_INIT; 450 if (f != 0) cerr << ','; 451 } 452 if ((f & TE_PRUNE) != 0) { 453 cerr << "prune"; 454 f -= TE_PRUNE; 455 if (f != 0) cerr << ','; 456 } 457 if ((f & TE_FIX) != 0) { 458 cerr << "fix"; 459 f -= TE_FIX; 460 if (f != 0) cerr << ','; 461 } 462 if ((f & TE_FAIL) != 0) { 463 cerr << "fail"; 464 f -= TE_FAIL; 465 if (f != 0) cerr << ','; 466 } 467 if ((f & TE_DONE) != 0) { 468 cerr << "done"; 469 f -= TE_DONE; 470 if (f != 0) cerr << ','; 471 } 472 if ((f & TE_PROPAGATE) != 0) { 473 cerr << "propagate"; 474 f -= TE_PROPAGATE; 475 if (f != 0) cerr << ','; 476 } 477 if ((f & TE_COMMIT) != 0) { 478 cerr << "commit"; 479 f -= TE_COMMIT; 480 if (f != 0) cerr << ','; 481 } 482 if ((f & TE_POST) != 0) { 483 cerr << "post"; 484 } 485 } 486 cerr << endl << "\t\t" << exp << endl; 487 } 488 489 490 int ProfilerOption::parse(int argc, char* argv[]) { 491 if (char* a = argument(argc, argv)) { 492 char* sep = strchr(a, ','); 493 if (!sep) { 494 std::cerr << "Wrong argument \"" << a << "\" for option \"" << iopt << "\"" << std::endl; 495 exit(EXIT_FAILURE); 496 } 497 cur_execution_id = static_cast<unsigned int>(atoi(a)); 498 cur_port = atoi(sep + 1); 499 return 2; 500 } 501 return 0; 502 } 503 504 void ProfilerOption::help(void) { std::cerr << '\t' << iopt << " (unsigned int,int) default: " << cur_port << "," << cur_execution_id << std::endl << "\t\t" << exp << std::endl; } 505 506 507 } 508 509 void 510 BaseOptions::add(Driver::BaseOption& o) { 511 o.next = nullptr; 512 if (fst == nullptr) { 513 fst=&o; 514 } else { 515 lst->next=&o; 516 } 517 lst=&o; 518 } 519 BaseOptions::BaseOptions(const char* n) 520 : fst(nullptr), lst(nullptr), 521 _name(Driver::BaseOption::strdup(n)) {} 522 523 void 524 BaseOptions::name(const char* n) { 525 Driver::BaseOption::strdel(_name); 526 _name = Driver::BaseOption::strdup(n); 527 } 528 529 void 530 BaseOptions::help(void) { 531 std::cerr << "Gecode configuration information:" << std::endl 532 << " - Version: " << GECODE_VERSION << std::endl 533 << " - Variable types: "; 534#ifdef GECODE_HAS_INT_VARS 535 std::cerr << "BoolVar IntVar "; 536#endif 537#ifdef GECODE_HAS_SET_VARS 538 std::cerr << "SetVar "; 539#endif 540#ifdef GECODE_HAS_FLOAT_VARS 541 std::cerr << "FloatVar " 542 << std::endl 543 << " - Trigonometric and transcendental float constraints: "; 544#ifdef GECODE_HAS_MPFR 545 std::cerr << "enabled"; 546#else 547 std::cerr << "disabled"; 548#endif 549#endif 550 std::cerr << std::endl; 551 std::cerr << " - Thread support: "; 552#ifdef GECODE_HAS_THREADS 553 if (Support::Thread::npu() == 1) 554 std::cerr << "enabled (1 processing unit)"; 555 else 556 std::cerr << "enabled (" << Support::Thread::npu() 557 << " processing units)"; 558#else 559 std::cerr << "disabled"; 560#endif 561 std::cerr << std::endl 562 << " - Gist support: "; 563#ifdef GECODE_HAS_GIST 564 std::cerr << "enabled"; 565#else 566 std::cerr << "disabled"; 567#endif 568 std::cerr << std::endl 569 << " - CPProfiler support: "; 570#ifdef GECODE_HAS_CPPROFILER 571 std::cerr << "enabled"; 572#else 573 std::cerr << "disabled"; 574#endif 575 std::cerr << std::endl << std::endl 576 << "Options for " << name() << ":" << std::endl 577 << "\t-help, --help, -?" << std::endl 578 << "\t\tprint this help message" << std::endl; 579 for (Driver::BaseOption* o = fst; o != nullptr; o = o->next) 580 o->help(); 581 } 582 583 void 584 BaseOptions::parse(int& argc, char* argv[]) { 585 int c = argc; 586 char** v = argv; 587 next: 588 for (Driver::BaseOption* o = fst; o != nullptr; o = o->next) 589 if (int a = o->parse(c,v)) { 590 c -= a; v += a; 591 goto next; 592 } 593 if (c >= 2) { 594 if (!strcmp(v[1],"-help") || !strcmp(v[1],"--help") || 595 !strcmp(v[1],"-?")) { 596 help(); 597 exit(EXIT_SUCCESS); 598 } 599 } 600 // Copy remaining arguments 601 argc = c; 602 for (int i=1; i<argc; i++) 603 argv[i] = v[i]; 604 return; 605 } 606 607 BaseOptions::~BaseOptions(void) { 608 Driver::BaseOption::strdel(_name); 609 } 610 611 612 Options::Options(const char* n) 613 : BaseOptions(n), 614 615 _model("model","model variants"), 616 _symmetry("symmetry","symmetry variants"), 617 _propagation("propagation","propagation variants"), 618 _branching("branching","branching variants"), 619 _decay("decay","decay factor",1.0), 620 _seed("seed","random number generator seed",1U), 621 _step("step","step distance for float optimization",0.0), 622 623 _search("search","search engine variants"), 624 _solutions("solutions","number of solutions (0 = all)",1), 625 _threads("threads","number of threads (0 = #processing units)", 626 Search::Config::threads), 627 _c_d("c-d","recomputation commit distance",Search::Config::c_d), 628 _a_d("a-d","recomputation adaptation distance",Search::Config::a_d), 629 _d_l("d-l","discrepancy limit for LDS",Search::Config::d_l), 630 _node("node","node cutoff (0 = none, solution mode)"), 631 _fail("fail","failure cutoff (0 = none, solution mode)"), 632 _time("time","time (in ms) cutoff (0 = none, solution mode)"), 633 _assets("assets","#portfolio assets (#engines)",0), 634 _slice("slice","portfolio slice (in #failures)",Search::Config::slice), 635 _restart("restart","restart sequence type",RM_NONE), 636 _r_base("restart-base","base for geometric restart sequence", 637 Search::Config::base), 638 _r_scale("restart-scale","scale factor for restart sequence", 639 Search::Config::slice), 640 _nogoods("nogoods","whether to use no-goods from restarts",false), 641 _nogoods_limit("nogoods-limit","depth limit for no-good extraction", 642 Search::Config::nogoods_limit), 643 _relax("relax","probability for relaxing variable", 0.0), 644 _interrupt("interrupt","whether to catch Ctrl-C (true) or not (false)", 645 true), 646 647 _mode("mode","how to execute script",SM_SOLUTION), 648 _samples("samples","how many samples (time mode)",1), 649 _iterations("iterations","iterations per sample (time mode)",1), 650 _print_last("print-last", 651 "whether to only print the last solution (solution mode)", 652 false), 653 _out_file("file-sol", "where to print solutions " 654 "(supports stdout, stdlog, stderr)","stdout"), 655 _log_file("file-stat", "where to print statistics " 656 "(supports stdout, stdlog, stderr)","stdout"), 657 _trace(0) 658 659#ifdef GECODE_HAS_CPPROFILER 660 , 661 _profiler("cp-profiler", "use this execution id and port (comma separated) with CP-profiler") 662#endif 663 { 664 665 _mode.add(SM_SOLUTION, "solution"); 666 _mode.add(SM_TIME, "time"); 667 _mode.add(SM_STAT, "stat"); 668 _mode.add(SM_GIST, "gist"); 669 670 _restart.add(RM_NONE,"none"); 671 _restart.add(RM_CONSTANT,"constant"); 672 _restart.add(RM_LINEAR,"linear"); 673 _restart.add(RM_LUBY,"luby"); 674 _restart.add(RM_GEOMETRIC,"geometric"); 675 676 add(_model); add(_symmetry); add(_propagation); add(_ipl); 677 add(_branching); add(_decay); add(_seed); add(_step); 678 add(_search); add(_solutions); add(_threads); add(_c_d); add(_a_d); 679 add(_d_l); 680 add(_node); add(_fail); add(_time); add(_interrupt); 681 add(_assets); add(_slice); 682 add(_restart); add(_r_base); add(_r_scale); 683 add(_nogoods); add(_nogoods_limit); 684 add(_relax); 685 add(_mode); add(_iterations); add(_samples); add(_print_last); 686 add(_out_file); add(_log_file); add(_trace); 687#ifdef GECODE_HAS_CPPROFILER 688 add(_profiler); 689#endif 690 } 691 692 693 SizeOptions::SizeOptions(const char* e) 694 : Options(e), _size(0) {} 695 696 void 697 SizeOptions::help(void) { 698 Options::help(); 699 std::cerr << "\t(unsigned int) default: " << size() << std::endl 700 << "\t\twhich version/size for script" << std::endl; 701 } 702 703 void 704 SizeOptions::parse(int& argc, char* argv[]) { 705 Options::parse(argc,argv); 706 if (argc < 2) 707 return; 708 size(static_cast<unsigned int>(atoi(argv[1]))); 709 } 710 711 712 713 InstanceOptions::InstanceOptions(const char* e) 714 : Options(e), _inst(nullptr) {} 715 716 void 717 InstanceOptions::instance(const char* s) { 718 Driver::BaseOption::strdel(_inst); 719 _inst = Driver::BaseOption::strdup(s); 720 } 721 722 void 723 InstanceOptions::help(void) { 724 Options::help(); 725 std::cerr << "\t(string) default: " << instance() << std::endl 726 << "\t\twhich instance for script" << std::endl; 727 } 728 729 void 730 InstanceOptions::parse(int& argc, char* argv[]) { 731 Options::parse(argc,argv); 732 if (argc < 2) 733 return; 734 instance(argv[1]); 735 } 736 737 InstanceOptions::~InstanceOptions(void) { 738 Driver::BaseOption::strdel(_inst); 739 } 740 741} 742 743// STATISTICS: driver-any