00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <clasp/cli/clasp_options.h>
00021 #include <clasp/minimize_constraint.h>
00022 #include <clasp/lookahead.h>
00023 #include <clasp/unfounded_check.h>
00024 #include <program_opts/program_options.h>
00025 #include <program_opts/typed_value.h>
00026 #include <cstring>
00027 #include <cstdarg>
00028 #include <cfloat>
00029 #include <fstream>
00031
00033
00034 #define IS_OFF(str) ( convFlag((str), TEMP) && TEMP == 0 )
00035 #define CONVERT(str, to) ( bk_lib::string_cast((str), (to)) )
00036 #define CONVERT_EX(str, to, n) ( xconvert((str), (to), &(str), (n)) && !*(str) )
00037 #define SET_ENUM(x, v, X, ...) ( findInValueList((v), x, X, ##__VA_ARGS__, MAP(0,0)) )
00038 #define SET_ENUM_U(x, v, X, ...)( findInValueList((v), TEMP, X, ##__VA_ARGS__, MAP(0,0)) && SET(x, TEMP) )
00039 #define SET(x, v) ( ((x)=(v)) == (v) )
00040 #define SET_LEQ(x, v, m) ( ((v)<=(m)) && SET((x), (v)) )
00041 #define SET_OR_FILL(x, v) ( SET((x),(v)) || ((x) = 0, (x) = ~(x),true) )
00042 #define SET_OR_ZERO(x,v) ( SET((x),(v)) || SET((x),uint32(0)) )
00043 #define SET_R(x, v, lo, hi) ( ((lo)<=(v)) && ((v)<=(hi)) && SET((x), (v)) )
00044
00045 #define STORE(x) return bk_lib::string_cast(VALUE, x)
00046 #define STORE_ENUM(x, X, ...) return SET_ENUM(x, VALUE, X, ##__VA_ARGS__)
00047 #define STORE_ENUM_U(x, X, ...) return SET_ENUM_U(x, VALUE, X, ##__VA_ARGS__)
00048 #define STORE_LEQ(x, y) STORE(TEMP) && SET_LEQ(x, TEMP, y)
00049 #define STORE_OR_ZERO(x) STORE(TEMP) && SET_OR_ZERO(x, TEMP)
00050 #define STORE_OR_FILL(x) STORE(TEMP) && SET_OR_FILL(x, TEMP)
00051 #define STORE_FLAG(x) return convFlag(VALUE,TEMP) && SET(x, TEMP)
00052
00053 #define MAP(x, y) static_cast<const char*>(x), static_cast<int>(y)
00054 #define NO_ARG
00055 #define PAIR(T, U) std::pair<T,U>
00056 #define AGGREGATE(...) { __VA_ARGS__ }
00057 typedef std::pair<uint32, uint32> UPair;
00058 #define ARG(a) ->a
00059 #define VALUE (_val_)
00060 #define TEMP (_tmp_)
00061 #define HEU_PARAM "hparam"
00062
00063
00065 namespace bk_lib {
00066 template <class T>
00067 static int xconvert(const char* x, pod_vector<T>& out, const char** errPos, int) {
00068 using bk_lib::xconvert;
00069 const char* n = x;
00070 std::size_t s = out.size();
00071 for (T temp; xconvert(n, temp, &n, 0); ++n) {
00072 out.push_back(temp);
00073 if (*n != ',') { break; }
00074 }
00075 if (errPos) { *errPos = n; }
00076 return static_cast<int>(out.size() - s);
00077 }
00078 }
00079 namespace Clasp {
00080 static int xconvert(const char* x, ScheduleStrategy& out, const char** errPos, int e) {
00081 using bk_lib::xconvert;
00082 if (!x) { return 0; }
00083 const char* next = std::strchr(x, ',');
00084 uint32 base = 0;
00085 int tok = 1;
00086 if (errPos) { *errPos = x; }
00087 if (!next || !xconvert(next+1, base, &next, e) || base == 0) { return 0; }
00088 if (strncasecmp(x, "f,", 2) == 0 || strncasecmp(x, "fixed,", 6) == 0){
00089 out = ScheduleStrategy::fixed(base);
00090 }
00091 else if (strncasecmp(x, "l,", 2) == 0 || strncasecmp(x, "luby,", 5) == 0) {
00092 uint32 lim = 0;
00093 if (*next == ',' && !xconvert(next+1, lim, &next, e)) { return 0; }
00094 out = ScheduleStrategy::luby(base, lim);
00095 }
00096 else if (strncmp(x, "+,", 2) == 0 || strncasecmp(x, "add,", 4) == 0) {
00097 std::pair<uint32, uint32> arg(0, 0);
00098 if (*next != ',' || !xconvert(next+1, arg, &next, e)) { return 0; }
00099 out = ScheduleStrategy::arith(base, arg.first, arg.second);
00100 }
00101 else if (strncmp(x, "x,", 2) == 0 || strncmp(x, "*,", 2) == 0 || strncasecmp(x, "d,", 2) == 0) {
00102 std::pair<double, uint32> arg(0, 0);
00103 if (*next != ',' || !xconvert(next+1, arg, &next, e)) { return 0; }
00104 if (strncasecmp(x, "d", 1) == 0 && arg.first > 0.0) { out = ScheduleStrategy(ScheduleStrategy::user_schedule, base, arg.first, arg.second); }
00105 else if (strncasecmp(x, "d", 1) != 0 && arg.first >= 1.0){ out = ScheduleStrategy::geom(base, arg.first, arg.second); }
00106 else { return 0; }
00107 }
00108 else { next = x; tok = 0; }
00109 if (errPos) { *errPos = next; }
00110 return tok;
00111 }
00112 namespace Cli {
00113 static bool findInValueListImpl(const char* value, int& out, const char* k1, int v1, va_list args) {
00114 if (strcasecmp(value, k1) == 0) { out = v1; return true; }
00115 while (const char* key = va_arg(args, const char *)) {
00116 int val = va_arg(args, int);
00117 if (strcasecmp(value, key) == 0) { out = val; return true; }
00118 }
00119 return false;
00120 }
00121
00122 template <class T>
00123 static bool findInValueList(const char* value, T& out, const char* k1, int v1, ...) {
00124 va_list args;
00125 va_start(args, v1);
00126 int temp;
00127 bool found;
00128 if ((found = findInValueListImpl(value, temp, k1, v1, args)) == true) {
00129 out = static_cast<T>(temp);
00130 }
00131 va_end(args);
00132 return found;
00133 }
00134 template <class T>
00135 static bool convFlag(const char* value, T& out) {
00136 bool res;
00137 if (value && bk_lib::xconvert(value, res, &value, 0) && !*value) { out = static_cast<T>(res); return true; }
00138 return false;
00139 }
00141
00143
00144 class ClaspCliConfig::ProgOption : public ProgramOptions::Value {
00145 public:
00146 ProgOption(ClaspCliConfig& c, int o) : ProgramOptions::Value(0), config_(&c), option_(o) {}
00147 bool doParse(const std::string&, const std::string& value) {
00148 return option_ >= 0 ? config_->set(static_cast<Clasp::Cli::OptionKey>(option_), value.c_str()) : config_->set(static_cast<ConfigOption>(option_), value.c_str());
00149 }
00150 int option() const { return option_; }
00151 private:
00152 ClaspCliConfig* config_;
00153 int option_;
00154 };
00155
00156 struct ClaspCliConfig::ParseContext : public ProgramOptions::ParseContext {
00157 typedef ProgramOptions::SharedOptPtr OptPtr;
00158 typedef OptionContext::option_iterator OptionIter;
00159 ParseContext() : root(0) {}
00160 void init() {
00161 first = root->find("configuration");
00162 OptionIter it = root->find(HEU_PARAM);
00163 root->addAlias("vsids-decay", it);
00164 root->addAlias("berk-max", it);
00165 root->addAlias("vmtf-mtf", it);
00166 }
00167
00168 OptPtr getOption(const char* name, FindType ft) {
00169 OptionIter it = (root->begin() + root->findImpl(name, ft, 3u, frame->config).first->second);
00170 OptionIter end = first + (option_category_end - 4) + 2;
00171 if (it >= first && it < end && static_cast<const ProgOption*>(it->get()->value())->option() >= frame->minKey) { return *it; }
00172 throw ProgramOptions::UnknownOption(frame->config, name);
00173 }
00174 OptPtr getOption(int, const char* key) { throw ProgramOptions::UnknownOption(frame->config, key); }
00175 void addValue(const OptPtr& key, const std::string& value) {
00176 using namespace ProgramOptions;
00177 Value::State s = Value::value_unassigned;
00178 if (frame->exclude->count(key->name()) == 0) {
00179 ProgOption* v = static_cast<ProgOption*>(key->value());
00180 int id = (v->option() - frame->minKey);
00181 uint64& xs = frame->seen[id/64];
00182 uint64 m = static_cast<uint64>(1u) << (id & 63);
00183 if ((xs & m) != 0 && !v->isComposing()){ throw ValueError(frame->config, ValueError::multiple_occurences, key->name(), value); }
00184 if (!v->parse(key->name(), value, s)) { throw ValueError(frame->config, ValueError::invalid_value, key->name(), value); }
00185 if (frame->out) { frame->out->add(key->name()); }
00186 xs |= m;
00187 }
00188 }
00189 RootPtr root;
00190 OptionIter first;
00191 struct Frame {
00192 uint64 seen[2];
00193 const char* config;
00194 const ParsedOpts* exclude;
00195 ParsedOpts* out;
00196 int minKey;
00197 }* frame;
00198 };
00200
00202 ClaspCliConfig::ConfigVec ClaspCliConfig::configs_g;
00203
00204 void ClaspCliConfig::appendConfig(ConfigKey k, const char* name, const char* cmd) {
00205 for ( name = name ? name : ""; *name == ' '; ++name) { ; }
00206 for ( cmd = cmd ? cmd : ""; *cmd == ' '; ++cmd ) { ; }
00207 std::string& out = configs_g[k - config_usr];
00208 out.erase(out.end()-1);
00209 out.append(1, '/');
00210 out.append(name);
00211 out.erase(out.find_last_not_of(" \t")+1);
00212 out.append("\0/", 2);
00213 out.append(cmd);
00214 out.erase(out.find_last_not_of(" \t")+1);
00215 out.append(2, '\0');
00216 }
00217
00218 ConfigKey ClaspCliConfig::allocConfig() {
00219 configs_g.reserve(2);
00220 unsigned key = (unsigned)configs_g.size() + config_usr;
00221 CLASP_FAIL_IF(key > config_usr_max_value, "Too many configs");
00222 configs_g.push_back(std::string());
00223 configs_g.back().reserve(128);
00224 configs_g.back().append(1, '\0');
00225 return static_cast<ConfigKey>(key);
00226 }
00227
00228 ConfigKey ClaspCliConfig::loadConfig(const char* name) {
00229 std::ifstream file(name);
00230 CLASP_FAIL_IF(!file, "Could not open config file '%s'", name);
00231 ConfigKey key = allocConfig();
00232 uint32 lineNum= 0;
00233 for (std::string line, cont; std::getline(file, line); ) {
00234 ++lineNum;
00235 line.erase(0, line.find_first_not_of(" \t"));
00236 if (line.empty() || line[0] == '#') { continue; }
00237 if (*line.rbegin() == '\\') { *line.rbegin() = ' '; cont += line; continue; }
00238 try {
00239 if (!cont.empty()) { cont += line; cont.swap(line); cont.clear(); }
00240 std::string::size_type nEnd = line.find(":");
00241 CLASP_FAIL_IF(!nEnd, "'%s@%u': Invalid empty name", name, lineNum);
00242 CLASP_FAIL_IF(nEnd == std::string::npos, "'%s@%u': Expected ':' after name", name, lineNum);
00243 line[nEnd] = '\0';
00244 line.append(1, '\0');
00245 appendConfig(key, &line[0], &line[nEnd+1]);
00246 }
00247 catch(...) { releaseConfig(key); throw; }
00248 }
00249 return key;
00250 }
00251
00252 bool ClaspCliConfig::releaseConfig(ConfigKey key) {
00253 if (key >= config_usr) {
00254 configs_g.at(unsigned(key - config_usr)).clear();
00255 while (!configs_g.empty() && configs_g.back().empty()) { configs_g.pop_back(); }
00256 return true;
00257 }
00258 return false;
00259 }
00260
00261 ConfigIter ClaspCliConfig::getConfig(ConfigKey key) {
00262 switch(key) {
00263 #define CONFIG(x,y,z) case config_##x: return ConfigIter("/[" #x "]\0/" y " " z "\0");
00264 #define CLASP_CLI_DEFAULT_CONFIGS
00265 #define CLASP_CLI_AUX_CONFIGS
00266 #include <clasp/cli/clasp_cli_configs.inl>
00267 case config_many:
00268 #define CONFIG(x,y,z) "/[" #x "]\0/" z "\0"
00269 #define CLASP_CLI_DEFAULT_CONFIGS
00270 #define CLASP_CLI_AUX_CONFIGS
00271 return ConfigIter(
00272 #include <clasp/cli/clasp_cli_configs.inl>
00273 );
00274 case config_default: return ConfigIter("/default\0/\0");
00275 case config_usr:
00276 default : return ConfigIter(configs_g.at(unsigned(key - config_usr)).data());
00277 }
00278 }
00279 const char* ClaspCliConfig::getDefaults(ProblemType t) {
00280 if (t == Problem_t::ASP){ return "--configuration=tweety"; }
00281 else { return "--configuration=trendy"; }
00282 }
00283 ConfigIter::ConfigIter(const char* x) : base_(x) {}
00284 const char* ConfigIter::name() const { return base_ + 1; }
00285 const char* ConfigIter::args() const { return base_ + std::strlen(base_) + 2; }
00286 bool ConfigIter::valid()const { return *base_ != 0; }
00287 bool ConfigIter::next() {
00288 base_ = args();
00289 base_+= std::strlen(base_) + 1;
00290 return valid();
00291 }
00293
00295 ClaspCliConfig::ScopedSet::ScopedSet(ClaspCliConfig& s, uint8 mode, uint32 sId) : self(&s) {
00296 if (sId) { mode |= mode_solver; }
00297 s.cliId = static_cast<uint8>(sId);
00298 s.cliMode = mode;
00299 }
00300 ClaspCliConfig::ScopedSet::~ScopedSet() { self->cliId = self->cliMode = 0; }
00301 ClaspCliConfig::RawConfig::RawConfig(const char* name) {
00302 raw.append(1, '/').append(name ? name : "").append("\0/\0", 3);
00303 }
00304 void ClaspCliConfig::RawConfig::addArg(const char* arg) {
00305 *raw.rbegin() = ' ';
00306 raw.append(arg ? arg : "").append(1, '\0');
00307 }
00308 void ClaspCliConfig::RawConfig::addArg(const std::string& arg) { addArg(arg.c_str()); }
00309 ClaspCliConfig::ClaspCliConfig() {}
00310 ClaspCliConfig::~ClaspCliConfig() {}
00311 ClaspCliConfig::ProgOption* ClaspCliConfig::createOption(int o) { return new ProgOption(*this, o); }
00312
00313 void ClaspCliConfig::init(OptionContext* root, bool owned) {
00314 #if WITH_THREADS
00315 #define MANY_DESC " many : Use default portfolio to configure solver(s)\n"
00316 #define MANY_ARG "|many"
00317 #else
00318 #define MANY_DESC
00319 #define MANY_ARG ""
00320 #endif
00321 using namespace ProgramOptions;
00322 if (opts_.get() == 0) { opts_ = new ParseContext(); }
00323 if (owned || !opts_->root.get() || !opts_->root.is_owner()) {
00324 opts_->root = root;
00325 if (!owned) opts_->root.release();
00326 }
00327 OptionGroup configOpts("Clasp.Config Options");
00328 configOpts.addOptions()
00329 ("configuration", createOption(opt_configuration)->defaultsTo("auto")->state(Value::value_defaulted), "Configure default configuration [%D]\n"
00330 " %A: {auto|frumpy|jumpy|tweety|handy|crafty|trendy" MANY_ARG "|<file>}\n"
00331 " auto : Select configuration based on problem type\n"
00332 " frumpy: Use conservative defaults\n"
00333 " jumpy : Use aggressive defaults\n"
00334 " tweety: Use defaults geared towards asp problems\n"
00335 " handy : Use defaults geared towards large problems\n"
00336 " crafty: Use defaults geared towards crafted problems\n"
00337 " trendy: Use defaults geared towards industrial problems\n"
00338 MANY_DESC
00339 " <file>: Use configuration file to configure solver(s)")
00340 ("tester", createOption(opt_tester)->arg("<options>"), "Pass (quoted) string of %A to tester")
00341 ;
00342 #undef MANY_DESC
00343 #undef MANY_ARG
00344 OptionGroup solving("Clasp.Solving Options");
00345 OptionGroup asp("Clasp.ASP Options");
00346 OptionGroup search("Clasp.Search Options", ProgramOptions::desc_level_e1);
00347 OptionGroup lookback("Clasp.Lookback Options", ProgramOptions::desc_level_e1);
00348 #define OPTION(n, k, a, d, x) (n,createOption(opt_##k)a, d)
00349 #define GROUP_BEGIN(X) X.addOptions()
00350 #define GROUP_END(X) ;
00351 #define CLASP_CONTEXT_OPTIONS configOpts
00352 #define CLASP_SOLVE_OPTIONS solving
00353 #define CLASP_ENUM_OPTIONS solving
00354 #define CLASP_ASP_OPTIONS asp
00355 #define CLASP_SOLVER_BASIC_OPTIONS search
00356 #define CLASP_SEARCH_BASIC_OPTIONS search
00357 #define CLASP_SOLVER_LOOKBACK_OPTIONS lookback
00358 #define CLASP_SEARCH_RESTART_OPTIONS lookback
00359 #define CLASP_SEARCH_REDUCE_OPTIONS lookback
00360 #include <clasp/cli/clasp_cli_options.inl>
00361 root->add(configOpts);
00362 root->add(solving);
00363 root->add(asp);
00364 root->add(search);
00365 root->add(lookback);
00366 opts_->init();
00367 }
00368
00369 void ClaspCliConfig::addOptions(OptionContext& root) {
00370 init(&root, false);
00371 }
00372
00373 int ClaspCliConfig::get(OptionKey oId, ContextParams*& ctx, SolverParams*& solver, SolveParams*& solve) {
00374 UserConfig* active = this->active();
00375 uint32 sId = cliId;
00376 if (oId < option_category_search) { solver = &active->addSolver(sId); return oId; }
00377 if (oId < option_category_context) { solve = &active->addSearch(sId); return oId; }
00378 if (oId < option_category_generator || isGenerator()) {
00379 ctx = active;
00380 if ((cliMode & mode_solver) == 0) { return oId; }
00381 if ((cliMode & mode_relaxed)!= 0) { return 0; }
00382 }
00383 return (cliMode & mode_relaxed) != 0 && oId < option_category_end ? 0 : option_category_end;
00384 }
00385
00386 void ClaspCliConfig::init(uint32 sId, ConfigKey c) {
00387 if (c != config_default) {
00388 ScopedSet(*this, mode_relaxed, sId)->set(getConfig(c), false, ParsedOpts(), 0);
00389 }
00390 }
00391 void ClaspCliConfig::initTester(uint32 sId, ConfigKey c) {
00392 if (c != config_default) {
00393 ScopedSet(*this, mode_tester|mode_relaxed, sId)->set(getConfig(c), false, ParsedOpts(), 0);
00394 }
00395 }
00396
00397 bool ClaspCliConfig::setTester(uint32 solverId, OptionKey o, const char* value) {
00398 addTesterConfig();
00399 return ScopedSet(*this, mode_tester, solverId)->set(o, value);
00400 }
00401 bool ClaspCliConfig::set(uint32 id, OptionKey o, const char* value) {
00402 return ScopedSet(*this, 0, id)->set(o,value);
00403 }
00404 bool ClaspCliConfig::set(Clasp::Cli::OptionKey o, const char* _val_) {
00405 using bk_lib::xconvert;
00406 unsigned _tmp_;
00407 SolverOpts* solver = 0;
00408 SearchOpts* search = 0;
00409 ContextParams* ctxOpts= 0;
00410 switch(get(o, ctxOpts, solver, search)) {
00411 case 0: return true;
00412 default: error(o); return false;
00413 #define OPTION(n, k, a, d, x) case opt_##k: x ;
00414 #define CLASP_CONTEXT_OPTIONS (*ctxOpts)
00415 #define CLASP_ASP_OPTIONS asp
00416 #define CLASP_ENUM_OPTIONS enumerate
00417 #define CLASP_SOLVE_OPTIONS solve
00418 #define CLASP_SOLVER_BASIC_OPTIONS (*solver)
00419 #define CLASP_SOLVER_LOOKBACK_OPTIONS (*solver)
00420 #define CLASP_SEARCH_BASIC_OPTIONS (*search)
00421 #define CLASP_SEARCH_RESTART_OPTIONS search->restart
00422 #define CLASP_SEARCH_REDUCE_OPTIONS search->reduce
00423 #include <clasp/cli/clasp_cli_options.inl>
00424 }
00425 }
00426 bool ClaspCliConfig::set(ConfigOption o, const char* _val_) {
00427 uint8 _tmp_;
00428 if (o == opt_configuration) {
00429 return SET_ENUM_U(active()->cliConfig, _val_,
00430 MAP("auto", config_default), MAP("frumpy", config_frumpy), MAP("jumpy", config_jumpy),
00431 MAP("tweety", config_tweety) , MAP("handy" , config_handy) ,
00432 MAP("crafty", config_crafty) , MAP("trendy", config_trendy), MAP("many", config_many))
00433 || (active()->cliConfig=(uint8)ClaspCliConfig::loadConfig(VALUE)) != 0;
00434 }
00435 else if (o == opt_tester && isGenerator()) {
00436 ConfigKey key = allocConfig();
00437 addTesterConfig()->cliConfig = static_cast<uint8>(key);
00438 appendConfig(key, "<tester>", _val_);
00439 return true;
00440 }
00441 error(o);
00442 return false;
00443 }
00444 bool ClaspCliConfig::setDefaults(UserConfig* active, uint32 sId, const ParsedOpts& cmdLine, ProblemType t) {
00445 ScopedSet temp(*this, (active == this ? 0 : mode_tester) | mode_relaxed, sId);
00446 if (sId == 0 && t != Problem_t::ASP && cmdLine.count("sat-prepro") == 0) {
00447 set(opt_sat_prepro, "20,25,120");
00448 }
00449 if (active->addSolver(sId).search == SolverParams::no_learning) {
00450 if (cmdLine.count("heuristic") == 0) { set(opt_heuristic, "unit"); }
00451 if (cmdLine.count("lookahead") == 0) { set(opt_lookahead, "atom"); }
00452 if (cmdLine.count("deletion") == 0) { set(opt_deletion, "no"); }
00453 if (cmdLine.count("restarts") == 0) { set(opt_restarts, "no"); }
00454 }
00455 return true;
00456 }
00457
00458 bool ClaspCliConfig::set(const ConfigIter& config, bool allowConfig, const ParsedOpts& exclude, ParsedOpts* out) {
00459 if (!opts_.get() || !opts_->root.get()) { init(new OptionContext(), true); }
00460 ParseContext::Frame frame = { {uint64(0),uint64(0)}, config.name(), &exclude, out, (allowConfig ? -2 : 0) };
00461 opts_->frame = &frame;
00462 ProgramOptions::parseCommandString(config.args(), *opts_, ProgramOptions::command_line_allow_flag_value);
00463 return true;
00464 }
00465
00466 bool ClaspCliConfig::finalize() {
00467 UserConfiguration* arr[3] = { this, testerConfig(), 0 };
00468 UserConfiguration** c = arr;
00469 char ctx[80];
00470 do {
00471 for (uint32 i = 0; i != (*c)->numSolver(); ++i) {
00472 validate(clasp_format(ctx, 80, "<%s>.%u", *c == this ? "<config>":"<tester>", i), (*c)->solver(i), (*c)->search(i));
00473 }
00474 } while (*++c);
00475 return true;
00476 }
00477
00478 bool ClaspCliConfig::finalize(const ParsedOpts& x, ProblemType t, bool defs) {
00479 ParsedOpts temp;
00480 if (!finalizeSolvers(this, finalizeParsed(this, x, temp), t, defs)){ return false; }
00481 if (!finalizeTester(defs)) { return false; }
00482 if (opts_.get() && !opts_->root.is_owner()) { opts_->root = 0; }
00483 return true;
00484 }
00485
00486 bool ClaspCliConfig::finalizeTester(bool defs) {
00487 if (BasicSatConfig* tester = testerConfig()) {
00488 ParsedOpts ex;
00489 ConfigKey key = static_cast<ConfigKey>(tester->cliConfig);
00490 if ((tester->cliConfig & opt_applied) == 0) {
00491 tester->cliConfig = 0;
00492 if (!ScopedSet(*this, mode_tester)->set(getConfig(key), true, ParsedOpts(), &ex)) {
00493 return false;
00494 }
00495 releaseConfig(key);
00496 }
00497 return finalizeSolvers(testerConfig(), finalizeParsed(testerConfig(), ex, ex), Problem_t::ASP, defs);
00498 }
00499 return true;
00500 }
00501
00502 void ClaspCliConfig::addDisabled(ParsedOpts& parsed) {
00503 finalizeParsed(this, parsed, parsed);
00504 }
00505
00506 const ClaspCliConfig::ParsedOpts& ClaspCliConfig::finalizeParsed(UserConfig* active, const ParsedOpts& parsed, ParsedOpts& exclude) const {
00507 bool copied = &parsed == &exclude;
00508 if (active->search(0).reduce.fReduce() == 0 && parsed.count("deletion") != 0) {
00509 if (!copied) { exclude = parsed; copied = true; }
00510 exclude.add("del-cfl");
00511 exclude.add("del-max");
00512 exclude.add("del-grow");
00513 }
00514 CLASP_FAIL_IF(parsed.count(HEU_PARAM) && !parsed.count("heuristic"), "'--" HEU_PARAM "' requires '--heuristic'");
00515 if (parsed.count("heuristic") && !parsed.count(HEU_PARAM)) {
00516 if (!copied) { exclude = parsed; copied = true; }
00517 exclude.add(HEU_PARAM);
00518 active->addSolver(0).heuParam = 0;
00519 }
00520 return !copied ? parsed : exclude;
00521 }
00522
00523 bool ClaspCliConfig::finalizeSolvers(UserConfig* active, const ParsedOpts& parsed, ProblemType t, bool defs) {
00524 if (defs && !setDefaults(active, 0, parsed, t)) { return false; }
00525 SolverParams defSolver = active->solver(0);
00526 SolveParams defSearch = active->search(0);
00527 const char* ctx = active == testerConfig() ? "<tester>" : "<config>";
00528 validate(ctx, defSolver, defSearch);
00529 if ((active->cliConfig & opt_applied) != 0) {
00530 return true;
00531 }
00532 ConfigKey c = static_cast<ConfigKey>(active->cliConfig);
00533 if (c == config_many && solve.numSolver() == 1) { c = config_default; }
00534 if (c == config_default) {
00535 if (defSolver.search == SolverParams::no_learning) { c = config_nolearn; }
00536 else if (active == testerConfig()) { c = config_tester_default; }
00537 else if (solve.numSolver() == 1 || !solve.defaultPortfolio()) { c = t == Problem_t::ASP ? config_asp_default : config_sat_default; }
00538 else { c = config_many; }
00539 }
00540 ConfigIter conf = getConfig(c);
00541 uint8 mode = (active == testerConfig() ? mode_tester : 0) | mode_relaxed;
00542 uint32 portSize = 0;
00543 char buf[80];
00544 for (uint32 i = 0; i != solve.numSolver() && conf.valid(); ++i) {
00545 SolverParams& solver = (active->addSolver(i) = defSolver);
00546 SolveParams& search = (active->addSearch(i) = defSearch);
00547 solver.id = i;
00548 if (!ScopedSet(*this, mode, i)->set(conf, false, parsed, 0)) {
00549 return false;
00550 }
00551 validate(clasp_format(buf, 80, "%s.%s", ctx, conf.name()), solver, search);
00552 ++portSize;
00553 conf.next();
00554 mode |= mode_solver;
00555 }
00556 if (portSize != solve.numSolver()) {
00557 active->seed = (c >= config_many || solve.defaultPortfolio() || c == config_nolearn);
00558 }
00559 if (releaseConfig(c)) {
00560 active->cliConfig = 0;
00561 }
00562 active->cliConfig |= opt_applied;
00563 return true;
00564 }
00565
00566 void ClaspCliConfig::error(int opt) const {
00567 const char* optName = "???";
00568 switch(opt) {
00569 default: break;
00570 case opt_configuration: optName = "configuration"; break;
00571 case opt_tester : optName = "tester"; break;
00572 #define OPTION(n, k, a, d, x) case opt_##k: optName = n; break;
00573 #define CLASP_CONTEXT_OPTIONS
00574 #define CLASP_ASP_OPTIONS
00575 #define CLASP_ENUM_OPTIONS
00576 #define CLASP_SOLVE_OPTIONS
00577 #define CLASP_SOLVER_BASIC_OPTIONS
00578 #define CLASP_SOLVER_LOOKBACK_OPTIONS
00579 #define CLASP_SEARCH_BASIC_OPTIONS
00580 #define CLASP_SEARCH_RESTART_OPTIONS
00581 #define CLASP_SEARCH_REDUCE_OPTIONS
00582 #include <clasp/cli/clasp_cli_options.inl>
00583 }
00584 const char* end = optName;
00585 while (*end && *end != ',' && *end != '!') { ++end; }
00586 throw ProgramOptions::UnknownOption(isGenerator() ? "<clasp>" : "<tester>", std::string(optName, end - optName));
00587 }
00588
00589 bool ClaspCliConfig::setConfig(const RawConfig& config, ProblemType t) {
00590 ProgramOptions::ParsedOptions exclude;
00591 reset();
00592 return set(config.iterator(), true, exclude, &exclude) && opts_->root->assignDefaults(exclude) && finalize(exclude, t, true);
00593 }
00594
00595 void validate(const char* ctx, const SolverParams& solver, const SolveParams& search) {
00596 if (!ctx) { ctx = "<clasp>"; }
00597 const ReduceParams& reduce = search.reduce;
00598 if (solver.search == SolverParams::no_learning) {
00599 CLASP_FAIL_IF(Heuristic_t::isLookback(solver.heuId), "'%s': Heuristic requires lookback strategy!", ctx);
00600 CLASP_FAIL_IF(!search.restart.sched.disabled() && !search.restart.sched.defaulted(), "'%s': 'no-lookback': restart options disabled!", ctx);
00601 CLASP_FAIL_IF(!reduce.cflSched.disabled() || (!reduce.growSched.disabled() && !reduce.growSched.defaulted()) || search.reduce.fReduce() != 0, "'%s': 'no-lookback': deletion options disabled!", ctx);
00602 }
00603 bool hasSched = !reduce.cflSched.disabled() || !reduce.growSched.disabled() || reduce.maxRange != UINT32_MAX;
00604 CLASP_FAIL_IF(hasSched && reduce.fReduce() == 0.0f && !reduce.growSched.defaulted(), "'%s': 'no-deletion': deletion strategies disabled!", ctx);
00605 CLASP_FAIL_IF(!hasSched && reduce.fReduce() != 0.0f && !reduce.growSched.defaulted(), "'%s': 'deletion': deletion strategy required!", ctx);
00606 }
00607
00608 }}