1 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 2 3 /* 4 * Main authors: 5 * Guido Tack <guido.tack@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 #pragma once 13 14 #include <minizinc/exception.hh> 15 16 #include <string> 17 #include <unordered_map> 18 #include <utility> 19 #include <vector> 20 21 namespace MiniZinc { 22 class SolverConfigs; 23 24 /** 25 * \brief Configuration data for individual MiniZinc solvers 26 */ 27 class SolverConfig { 28 public: 29 /// Extra command line flags supported by solver 30 struct ExtraFlag { 31 enum FlagType { T_BOOL, T_INT, T_FLOAT, T_STRING }; 32 std::string flag; 33 std::string description; 34 FlagType flagType; 35 std::vector<std::string> range; 36 std::string defaultValue; ExtraFlagMiniZinc::SolverConfig::ExtraFlag37 ExtraFlag(std::string f, std::string d, FlagType t = T_BOOL, std::vector<std::string> r = {}, 38 std::string v = "false") 39 : flag(std::move(f)), 40 description(std::move(d)), 41 flagType(t), 42 range(std::move(r)), 43 defaultValue(std::move(v)) {} 44 45 bool validate(const std::string& v) const; 46 }; 47 48 protected: 49 /// The configuration file for this solver (or empty string for built-in solvers) 50 std::string _configFile; 51 /// The unique identifier for the solver 52 std::string _id; 53 /// Name of the solver (used for output) 54 std::string _name; 55 /// The path to the executable 56 std::string _executable; 57 /// The path to the executable, after resolving 58 std::string _executableResolved; 59 /// The path to the solver's MiniZinc library 60 std::string _mznlib; 61 /// The path to the solver's MiniZinc library, after resolving 62 std::string _mznlibResolved; 63 /// Version string 64 std::string _version; 65 /// MiniZinc library version 66 int _mznlibVersion = 1; 67 /// Short description 68 std::string _description; 69 /// Contact email 70 std::string _contact; 71 /// URL for more information 72 std::string _website; 73 /// Whether solver supports MiniZinc input 74 bool _supportsMzn = false; 75 /// Whether solver supports FlatZinc input 76 bool _supportsFzn = true; 77 /// Whether solver supports NL input 78 bool _supportsNL = false; 79 /// Whether solver requires solutions2out processing 80 bool _needsSolns2Out = true; 81 /// Whether solver is a GUI application 82 bool _isGUIApplication = false; 83 /// Whether solver needs path to minizinc executable (passed as --minizinc-exe) 84 bool _needsMznExecutable = false; 85 /// Whether solver needs path to MiniZinc standard library (passed as --stdlib-dir) 86 bool _needsStdlibDir = false; 87 /// Whether solver needs path to symbol table (paths file) (passed as --paths) 88 bool _needsPathsFile = false; 89 /// Supported standard command line flags 90 std::vector<std::string> _stdFlags; 91 /// Supported extra command line flags (flag and description) 92 std::vector<ExtraFlag> _extraFlags; 93 /// Required command line flags 94 std::vector<std::string> _requiredFlags; 95 /// Default command line flags (imported from global or user configuration) 96 std::vector<std::string> _defaultFlags; 97 /// Tags 98 std::vector<std::string> _tags; 99 100 public: 101 /// Load solver configuration from \a filename 102 static SolverConfig load(const std::string& filename); 103 /// Default constructor SolverConfig()104 SolverConfig() {} 105 /// Constructor SolverConfig(std::string id,std::string version)106 SolverConfig(std::string id, std::string version) 107 : _id(std::move(id)), _version(std::move(version)) {} 108 /// Return identifier id() const109 std::string id() const { return _id; } 110 /// Return version string version() const111 std::string version() const { return _version; } 112 113 /// Return configuration file name configFile() const114 std::string configFile() const { return _configFile; } 115 /// Set configuration file name configFile(const std::string & s)116 void configFile(const std::string& s) { _configFile = s; } 117 118 /// Return name name() const119 std::string name() const { return _name; } 120 // Set name name(const std::string & s)121 void name(const std::string& s) { _name = s; } 122 123 /// Return executable path executable() const124 std::string executable() const { return _executable; } 125 /// Set executable path executable(const std::string & s)126 void executable(const std::string& s) { _executable = s; } 127 128 /// Return resolved executable path executableResolved() const129 std::string executableResolved() const { return _executableResolved; } 130 131 /// Return MiniZinc library path mznlib() const132 std::string mznlib() const { return _mznlib; } 133 /// Set MiniZinc library path mznlib(const std::string & s)134 void mznlib(const std::string& s) { _mznlib = s; } 135 136 /// Return resolved MiniZinc library path mznlibResolved() const137 std::string mznlibResolved() const { return _mznlibResolved; } 138 139 /// Return required MiniZinc library version mznlibVersion() const140 int mznlibVersion() const { return _mznlibVersion; } 141 /// Set required MiniZinc library version mznlibVersion(int i)142 void mznlibVersion(int i) { _mznlibVersion = i; } 143 144 /// Whether solver supports MiniZinc input supportsMzn() const145 bool supportsMzn() const { return _supportsMzn; } 146 /// Set whether solver supports MiniZinc input supportsMzn(bool b)147 void supportsMzn(bool b) { _supportsMzn = b; } 148 149 /// Whether solver supports FlatZinc input supportsFzn() const150 bool supportsFzn() const { return _supportsFzn; } 151 /// Set whether solver supports FlatZinc input supportsFzn(bool b)152 void supportsFzn(bool b) { _supportsFzn = b; } 153 154 /// Whether solver supports NL input supportsNL() const155 bool supportsNL() const { return _supportsNL; } 156 /// Set whether solver supports NL input supportsNL(bool b)157 void supportsNL(bool b) { _supportsNL = b; } 158 159 /// Whether solver requires solutions2out processing needsSolns2Out() const160 bool needsSolns2Out() const { return _needsSolns2Out; } 161 /// Set whether solver requires solutions2out processing needsSolns2Out(bool b)162 void needsSolns2Out(bool b) { _needsSolns2Out = b; } 163 164 /// Whether solver is a GUI application isGUIApplication() const165 bool isGUIApplication() const { return _isGUIApplication; } 166 /// Set whether solver is a GUI application isGUIApplication(bool b)167 void isGUIApplication(bool b) { _isGUIApplication = b; } 168 169 /// Whether solver needs path to minizinc executable (passed as --minizinc-exe) needsMznExecutable() const170 bool needsMznExecutable() const { return _needsMznExecutable; } 171 /// Set whether solver needs path to minizinc executable needsMznExecutable(bool b)172 void needsMznExecutable(bool b) { _needsMznExecutable = b; } 173 174 /// Whether solver needs path to MiniZinc standard library (passed as --stdlib-dir) needsStdlibDir() const175 bool needsStdlibDir() const { return _needsStdlibDir; } 176 /// Set whether solver needs path to MiniZinc standard library needsStdlibDir(bool b)177 void needsStdlibDir(bool b) { _needsStdlibDir = b; } 178 179 /// Whether solver needs path to symbol table (paths file) (passed as --paths) needsPathsFile() const180 bool needsPathsFile() const { return _needsPathsFile; } 181 /// Set whether solver needs path to symbol table (paths file) needsPathsFile(bool b)182 void needsPathsFile(bool b) { _needsPathsFile = b; } 183 184 /// Return short description description() const185 std::string description() const { return _description; } 186 /// Set short description description(const std::string & s)187 void description(const std::string& s) { _description = s; } 188 189 /// Return contact email contact() const190 std::string contact() const { return _contact; } 191 /// Set contact email contact(const std::string & s)192 void contact(const std::string& s) { _contact = s; } 193 194 /// Return web site URL website() const195 std::string website() const { return _website; } 196 /// Set web site URL website(const std::string & s)197 void website(const std::string& s) { _website = s; } 198 199 /// Return supported standard command line flags stdFlags() const200 const std::vector<std::string>& stdFlags() const { return _stdFlags; } 201 /// Set supported standard command line flags stdFlags(const std::vector<std::string> & f)202 void stdFlags(const std::vector<std::string>& f) { _stdFlags = f; } 203 204 /// Return supported extra command line flags extraFlags() const205 const std::vector<ExtraFlag>& extraFlags() const { return _extraFlags; } 206 /// Set supported extra command line flags extraFlags(const std::vector<ExtraFlag> & f)207 void extraFlags(const std::vector<ExtraFlag>& f) { _extraFlags = f; } 208 209 /// Return supported required command line flags requiredFlags() const210 const std::vector<std::string>& requiredFlags() const { return _requiredFlags; } 211 /// Set supported required command line flags requiredFlags(const std::vector<std::string> & f)212 void requiredFlags(const std::vector<std::string>& f) { _requiredFlags = f; } 213 214 /// Return default command line flags defaultFlags() const215 const std::vector<std::string>& defaultFlags() const { return _defaultFlags; } 216 /// Set default command line flags defaultFlags(const std::vector<std::string> & f)217 void defaultFlags(const std::vector<std::string>& f) { _defaultFlags = f; } 218 219 /// Return tags tags() const220 const std::vector<std::string>& tags() const { return _tags; } 221 /// Set tags tags(const std::vector<std::string> & t)222 void tags(const std::vector<std::string>& t) { _tags = t; } 223 224 /// Output as JSON 225 std::string toJSON(const SolverConfigs& configs) const; 226 227 /// Test equality operator ==(const SolverConfig & sc) const228 bool operator==(const SolverConfig& sc) const { 229 return _id == sc.id() && _version == sc.version(); 230 } 231 }; 232 233 /// A container for solver configurations 234 class SolverConfigs { 235 protected: 236 /// The solvers 237 std::vector<SolverConfig> _solvers; 238 typedef std::unordered_map<std::string, std::vector<int> > TagMap; 239 /// Mapping tags to vectors of solvers (indexed into _solvers) 240 TagMap _tags; 241 /// The default solver 242 std::string _defaultSolver; 243 /// The MiniZinc library directory 244 std::string _mznlibDir; 245 /// The solver configurations path 246 std::vector<std::string> _solverPath; 247 typedef std::unordered_map<std::string, std::string> DefaultMap; 248 /// Mapping from tag to default solver for that tag 249 DefaultMap _tagDefault; 250 typedef std::unordered_map<std::string, std::vector<std::string> > SolverDefaultMap; 251 /// Mapping from solver id to default options for that solver 252 SolverDefaultMap _solverDefaultOptions; 253 /// Add new solver configuration \a sc 254 void addConfig(const SolverConfig& sc); 255 256 public: 257 /** \brief Constructor loading configurations from \a solverpath 258 * 259 * Configuration files must be called config.msc and the path 260 * uses platform specific separators (: on Unix-like systems, ; on Windows). 261 */ 262 SolverConfigs(std::ostream& log); 263 264 /// Populate the solver configurations 265 void populate(std::ostream& log); 266 267 /// Return configuration for solver \a s 268 /// The string can be a comma separated list of tags, in which case a 269 /// solver that matches all tags will be returned. The tag can also be 270 /// a solver id. A concrete version can be requested using @<version>. 271 /// Examples: 272 /// config("gecode@6.1.0") would request a gecode solver of version 6.1.0 273 /// config("mip,internal") would request a MIP solver that uses the internal API 274 /// config("org.minizinc.mip.coin-bc@2.9/1.16 would request a specific version of OSICBC 275 const SolverConfig& config(const std::string& s); 276 /// Return list of all solver ids 277 std::vector<std::string> solvers() const; 278 /// Return search path for solver configs 279 std::vector<std::string> solverConfigsPath() const; 280 /// Return JSON list of all solver configurations 281 std::string solverConfigsJSON() const; 282 /// Add a built-in solver 283 static void registerBuiltinSolver(const SolverConfig& sc); 284 285 /// Default solver defaultSolver() const286 const std::string& defaultSolver() const { return _defaultSolver; } 287 /// Default solver for tag \a t defaultSolver(const std::string & t) const288 const std::string& defaultSolver(const std::string& t) const { 289 static std::string noDefault; 290 auto it = _tagDefault.find(t); 291 return it == _tagDefault.end() ? noDefault : it->second; 292 } 293 /// MiniZinc library directory mznlibDir() const294 const std::string& mznlibDir() const { return _mznlibDir; } 295 /// Default options for the solver with the given ID 296 std::vector<std::string> defaultOptions(const std::string& id); 297 }; 298 299 /// An exception thrown when encountering an error in a solver configuration 300 class ConfigException : public Exception { 301 public: 302 /// Construct with message \a msg ConfigException(const std::string & msg)303 ConfigException(const std::string& msg) : Exception(msg) {} 304 /// Destructor ~ConfigException()305 ~ConfigException() throw() override {} 306 /// Return description what() const307 const char* what() const throw() override { return "MiniZinc: configuration error"; } 308 }; 309 } // namespace MiniZinc 310