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