7#include "delpi/util/ArgParser.h"
15#ifdef DELPI_ENABLED_QSOPTEX
16#include "delpi/libs/qsopt_ex.h"
18#ifdef DELPI_ENABLED_SOPLEX
19#include "delpi/libs/soplex.h"
22#include "delpi/util/OptionValue.hpp"
23#include "delpi/util/error.h"
24#include "delpi/util/filesystem.h"
25#include "delpi/util/logging.h"
26#include "delpi/version.h"
30#define DELPI_PARSE_PARAM_BOOL(parser, name, ...) \
32 parser.add_argument(__VA_ARGS__) \
33 .help(delpi::Config::help_##name) \
34 .default_value(delpi::Config::default_##name) \
35 .implicit_value(!delpi::Config::default_##name); \
38#define DELPI_PARSE_PARAM_SCAN(parser, name, scan_char, scan_type, ...) \
40 parser.add_argument(__VA_ARGS__) \
41 .help(delpi::Config::help_##name) \
42 .default_value(delpi::Config::default_##name) \
44 .scan<scan_char, scan_type>(); \
47#define DELPI_PARSE_PARAM_ENUM(parser, name, cmd_name, invalid_prompt, ...) \
49 parser.add_argument(cmd_name) \
50 .help(delpi::Config::help_##name) \
51 .default_value(delpi::Config::default_##name) \
52 .action([](const std::string &value) { \
54 DELPI_INVALID_ARGUMENT_EXPECTED(cmd_name, value, invalid_prompt); \
59#define DELPI_PARAM_TO_CONFIG(param_name, config_name, type) \
61 if (parser_.is_used(param_name)) config.m_##config_name().SetFromCommandLine(parser_.get<type>(param_name)); \
65 : parser_{DELPI_PROGRAM_NAME, DELPI_VERSION_STRING},
66#ifdef DELPI_ENABLED_QSOPTEX
67 qsoptex_hash_{QSopt_ex_repository_status()},
69#ifdef DELPI_ENABLED_SOPLEX
70 soplex_hash_{soplex::getGitHash()},
72 verbosity_{
Config::default_verbose_delpi} {
73 DELPI_TRACE(
"ArgParser::ArgParser");
82 DELPI_TRACE(
"ArgParser::parse: parsed args");
83 }
catch (
const std::runtime_error &err) {
84 std::cerr << err.what() <<
"\n" <<
parser_ << std::endl;
85 std::exit(EXIT_FAILURE);
86 }
catch (
const std::invalid_argument &err) {
87 std::cerr << err.what() <<
"\n\n" <<
parser_.usage() << std::endl;
88 std::exit(EXIT_FAILURE);
93 DELPI_TRACE(
"ArgParser::AddOptions: adding options");
94 parser_.add_description(prompt());
95 parser_.add_argument(
"file").help(
"input file").default_value(
"");
97 DELPI_PARSE_PARAM_BOOL(
parser_, csv,
"--csv");
98 DELPI_PARSE_PARAM_BOOL(
parser_, continuous_output,
"--continuous-output");
99 DELPI_PARSE_PARAM_BOOL(
parser_, debug_parsing,
"--debug-parsing");
100 DELPI_PARSE_PARAM_BOOL(
parser_, dry_run,
"--dry-run");
101 DELPI_PARSE_PARAM_BOOL(
parser_, skip_optimise,
"--skip-optimise");
102 DELPI_PARSE_PARAM_BOOL(
parser_, produce_models,
"-m",
"--produce-models");
103 DELPI_PARSE_PARAM_BOOL(
parser_, silent,
"-s",
"--silent");
104 DELPI_PARSE_PARAM_BOOL(
parser_, with_timings,
"-t",
"--timings");
105 DELPI_PARSE_PARAM_BOOL(
parser_, read_from_stdin,
"--in");
106 DELPI_PARSE_PARAM_BOOL(
parser_, verify,
"--verify");
109 DELPI_PARSE_PARAM_SCAN(
parser_, delta,
'g',
double,
"-d",
"--delta");
110 DELPI_PARSE_PARAM_SCAN(
parser_, random_seed,
'i',
unsigned int,
"-r",
"--random-seed");
111 DELPI_PARSE_PARAM_SCAN(
parser_, timeout,
'i',
unsigned int,
"--timeout");
112 DELPI_PARSE_PARAM_SCAN(
parser_, verbose_simplex,
'i',
int,
"--verbose-simplex");
114 parser_.add_argument(
"-V",
"--verbose")
115 .help(
"increase verbosity level. Can be used multiple times. Maximum verbosity level is 5 and default is 2")
116 .action([
this](
const auto &) {
121 parser_.add_argument(
"-q",
"--quiet")
122 .help(
"decrease verbosity level. Can be used multiple times. Minimum verbosity level is 0 and default is 2")
123 .action([
this](
const auto &) {
129 DELPI_PARSE_PARAM_ENUM(
131 "[ auto | pure-precision-boosting | pure-iterative-refinement | hybrid ] or [ 1 | 2 | 3 | 4 ]",
136 DELPI_PARSE_PARAM_ENUM(
137 parser_, format,
"--format",
"[ auto | mps ] or [ 1 | 2 ]",
140 DELPI_PARSE_PARAM_ENUM(
141 parser_, lp_solver,
"--lp-solver",
"[ soplex | qsoptex | delpi ] or [ 1 | 2 | 3 ]",
145 DELPI_TRACE(
"ArgParser::ArgParser: added all arguments");
149 DELPI_TRACE(
"ArgParser::ToConfig: converting to Config");
152 DELPI_PARAM_TO_CONFIG(
"csv", csv,
bool);
153 DELPI_PARAM_TO_CONFIG(
"continuous-output", continuous_output,
bool);
154 DELPI_PARAM_TO_CONFIG(
"debug-parsing", debug_parsing,
bool);
155 DELPI_PARAM_TO_CONFIG(
"dry-run", dry_run,
bool);
156 DELPI_PARAM_TO_CONFIG(
"delta", delta,
double);
162 DELPI_PARAM_TO_CONFIG(
"skip-optimise", skip_optimise,
bool);
163 DELPI_PARAM_TO_CONFIG(
"produce-models", produce_models,
bool);
164 DELPI_PARAM_TO_CONFIG(
"random-seed", random_seed,
unsigned int);
165 DELPI_PARAM_TO_CONFIG(
"in", read_from_stdin,
bool);
166 DELPI_PARAM_TO_CONFIG(
"silent", silent,
bool);
167 DELPI_PARAM_TO_CONFIG(
"timeout", timeout,
unsigned int);
169 DELPI_PARAM_TO_CONFIG(
"verbose-simplex", verbose_simplex,
int);
170 DELPI_PARAM_TO_CONFIG(
"verify", verify,
bool);
171 DELPI_PARAM_TO_CONFIG(
"timings", with_timings,
bool);
173 DELPI_TRACE_FMT(
"ArgParser::ToConfig: {}", config);
178 DELPI_TRACE(
"ArgParser::ValidateOptions: validating options");
180 DELPI_INVALID_ARGUMENT(
"--in",
"--in and file are mutually exclusive");
182 DELPI_INVALID_ARGUMENT(
"file",
"must be specified unless --in is used");
184 DELPI_INVALID_ARGUMENT(
"--in",
"a format must be specified with --format");
190 DELPI_INVALID_ARGUMENT(
"file",
"file must be .mps if --format is auto");
192 if (!std::filesystem::is_regular_file(
parser_.get<std::string>(
"file")))
193 DELPI_INVALID_ARGUMENT(
"file",
"cannot find file or the file is not a regular file");
195 if (
parser_.get<
double>(
"delta") < 0) DELPI_INVALID_ARGUMENT(
"--delta",
"cannot be negative");
197 DELPI_INVALID_ARGUMENT(
"--verbose",
"verbosity is forcefully set to 0 if --silent is provided");
199 DELPI_INVALID_ARGUMENT(
"--quiet",
"verbosity is already set to 0 if --silent is provided");
203 DELPI_INVALID_ARGUMENT(
"--lp-solver",
"QSopt_ex only supports 'auto' and 'pure-precision-boosting' modes");
206std::string ArgParser::version() {
return DELPI_VERSION_STRING; }
208std::string ArgParser::repository_status() {
return DELPI_VERSION_REPOSTAT; }
210std::string ArgParser::prompt()
const {
212 const std::string build_type{
"Debug"};
214 const std::string build_type{
"Release"};
216 std::string repo_stat = repository_status();
217 if (!repo_stat.empty()) {
218 repo_stat =
" (repository: " + repo_stat +
")";
221 std::string vstr = fmt::format(
"{} (v{}): {} ({} Build) {}", DELPI_PROGRAM_NAME, version(), DELPI_DESCRIPTION,
222 build_type, repo_stat);
223 if (!qsoptex_hash_.empty()) vstr += fmt::format(
" (qsopt-ex: {})", qsoptex_hash_);
224 if (!soplex_hash_.empty()) vstr += fmt::format(
" (soplex: {})", soplex_hash_);
228std::ostream &operator<<(std::ostream &os,
const ArgParser &parser) {
return os << parser.parser_ << std::endl; }
void Parse(int argc, const char **argv)
Parse the command line arguments.
int verbosity_
Verbosity level of the program.
Config ToConfig() const
Convert the parser to a Config.
void ValidateOptions()
Validate the options, ensuring the correctness of the parameters and the consistency of the options.
argparse::ArgumentParser parser_
The parser object.
void AddOptions()
Add all the options, positional arguments and flags to the parser.
Simple dataclass used to store the configuration of the program.
LpSolver
Underlying LP solver used by the theory solver.
@ SOPLEX
Soplex Solver. Default option.
LpMode
LP mode used by the LP solver.
@ HYBRID
Use both modes, if available.
@ PURE_PRECISION_BOOSTING
Use the precision boosting mode, if available.
@ AUTO
Let the LP solver choose the mode. Default option.
@ PURE_ITERATIVE_REFINEMENT
Use the iterative refinement mode, if available.
Format
Format of the input file.
@ AUTO
Automatically detect the input format based on the file extension. Default option.
void SetFromCommandLine(const T &value)
Sets the value to value which is given by a command-line argument.
Global namespace for the delpi library.
std::string GetExtension(const std::string &name)
Get the extension of the file.