From 444a75ff99dc4fe613aa2d6cb2eb85c741c71075 Mon Sep 17 00:00:00 2001 From: Brian Ward Date: Wed, 6 Aug 2025 11:50:59 -0400 Subject: [PATCH 1/7] Move build logic for examples to own file --- .github/workflows/ci.yml | 2 +- CMakeLists.txt | 14 +------------- examples/CMakeLists.txt | 11 +++++++++++ 3 files changed, 13 insertions(+), 14 deletions(-) create mode 100644 examples/CMakeLists.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 02ff1a9..ef4bc4e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,7 +58,7 @@ jobs: - name: Run examples run: | cd build/ - ./examples + ./examples/examples shell: bash - name: Test diff --git a/CMakeLists.txt b/CMakeLists.txt index c380803..53b5fd9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,10 +102,6 @@ if(WALNUTS_BUILD_STAN) target_include_directories(BridgeStan::BridgeStan INTERFACE "${CMAKE_BINARY_DIR}/_deps/bridgestan-src/src" ) - - add_executable(examples_stan ${CMAKE_CURRENT_SOURCE_DIR}/examples/examples_stan.cpp) - target_link_libraries(examples_stan PRIVATE Eigen3::Eigen nuts::nuts BridgeStan::BridgeStan) - target_compile_options(examples_stan PRIVATE -Wall) endif() ############################# @@ -132,17 +128,9 @@ add_library(nuts::nuts ALIAS walnuts) ## Examples ## ########################## if (WALNUTS_BUILD_EXAMPLES) - add_executable(examples ${CMAKE_CURRENT_SOURCE_DIR}/examples/examples.cpp) - target_link_libraries(examples PRIVATE nuts::nuts) - target_compile_options(examples PRIVATE -O3 -Wall) + add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/examples") endif() -########################## -## Extras ## -########################## -if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/extras/CMakeLists.txt") - add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/extras") -endif() ########################## ## Tests ## diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..b37d321 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,11 @@ +add_executable(examples examples.cpp) +target_link_libraries(examples PRIVATE nuts::nuts) +target_compile_options(examples PRIVATE -O3 -Wall) + + + +if(WALNUTS_BUILD_STAN) + add_executable(examples_stan examples_stan.cpp) + target_link_libraries(examples_stan PRIVATE Eigen3::Eigen nuts::nuts BridgeStan::BridgeStan) + target_compile_options(examples_stan PRIVATE -Wall) +endif() From 83763434815a4bc259b05de6cbd0718930f7679c Mon Sep 17 00:00:00 2001 From: Brian Ward Date: Wed, 6 Aug 2025 11:52:08 -0400 Subject: [PATCH 2/7] Clean up load_stan.hpp --- examples/load_stan.hpp | 63 +++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/examples/load_stan.hpp b/examples/load_stan.hpp index 9e9f528..61101bf 100644 --- a/examples/load_stan.hpp +++ b/examples/load_stan.hpp @@ -64,42 +64,43 @@ inline T dlsym_cast_impl(dynamic_library& library, const char* name) { #define dlsym_cast(library, func) \ dlsym_cast_impl(library, #func) -template -void no_op_deleter(T*) {} +using unique_bs_model = std::unique_ptr; + +inline unique_bs_model make_model(dynamic_library& library, const char* data, + unsigned int seed) { + auto model_construct = dlsym_cast(library, bs_model_construct); + auto model_destruct = dlsym_cast(library, bs_model_destruct); + char* err = nullptr; + auto model_ptr = + unique_bs_model(model_construct(data, seed, &err), model_destruct); + if (!model_ptr) { + if (err) { + std::string error_string(err); + dlsym_cast(library, bs_free_error_msg)(err); + throw std::runtime_error(error_string); + } + throw std::runtime_error("Failed to construct model"); + } + return model_ptr; +} class DynamicStanModel { public: DynamicStanModel(const char* model_path, const char* data, unsigned int seed) : library_(dlopen_safe(model_path)), - model_ptr_(nullptr, no_op_deleter), - rng_ptr_(nullptr, no_op_deleter) { - auto model_construct = dlsym_cast(library_, bs_model_construct); - auto model_destruct = dlsym_cast(library_, bs_model_destruct); + model_ptr_(make_model(library_, data, seed)), + free_error_msg_(dlsym_cast(library_, bs_free_error_msg)), + param_unc_num_(dlsym_cast(library_, bs_param_unc_num)), + param_num_(dlsym_cast(library_, bs_param_num)), + log_density_gradient_(dlsym_cast(library_, bs_log_density_gradient)), + param_constrain_(dlsym_cast(library_, bs_param_constrain)), + param_names_(dlsym_cast(library_, bs_param_names)), + rng_ptr_(nullptr, [](auto) {}) { + // temporary: we probably don't want to store the RNG in the model + // due to thread safety concerns auto rng_construct = dlsym_cast(library_, bs_rng_construct); auto rng_destruct = dlsym_cast(library_, bs_rng_destruct); - - free_error_msg_ = dlsym_cast(library_, bs_free_error_msg); - param_unc_num_ = dlsym_cast(library_, bs_param_unc_num); - param_num_ = dlsym_cast(library_, bs_param_num); - log_density_gradient_ = dlsym_cast(library_, bs_log_density_gradient); - param_constrain_ = dlsym_cast(library_, bs_param_constrain); - param_names_ = dlsym_cast(library_, bs_param_names); - char* err = nullptr; - model_ptr_ = std::unique_ptr( - model_construct(data, seed, &err), model_destruct); - - if (!model_ptr_) { - if (err) { - std::string error_string(err); - free_error_msg_(err); - throw std::runtime_error(error_string); - } - throw std::runtime_error("Failed to construct model"); - } - - // temporary: we probably don't want to store the RNG in the model - // due to thread safety concerns rng_ptr_ = std::unique_ptr( rng_construct(seed, &err), rng_destruct); if (!rng_ptr_) { @@ -177,15 +178,15 @@ class DynamicStanModel { } private: - std::unique_ptr library_; - std::unique_ptr model_ptr_; - std::unique_ptr rng_ptr_; + dynamic_library library_; + unique_bs_model model_ptr_; decltype(&bs_free_error_msg) free_error_msg_; decltype(&bs_param_unc_num) param_unc_num_; decltype(&bs_param_num) param_num_; decltype(&bs_log_density_gradient) log_density_gradient_; decltype(&bs_param_constrain) param_constrain_; decltype(&bs_param_names) param_names_; + std::unique_ptr rng_ptr_; }; #endif From 677f77a5849ee55971be7c83999b037cd18c115f Mon Sep 17 00:00:00 2001 From: Brian Ward Date: Wed, 6 Aug 2025 12:04:44 -0400 Subject: [PATCH 3/7] Add example that runs stan model with all options configurable --- examples/CMakeLists.txt | 13 ++ examples/stan_cli.cpp | 288 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 301 insertions(+) create mode 100644 examples/stan_cli.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index b37d321..78f2b66 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -8,4 +8,17 @@ if(WALNUTS_BUILD_STAN) add_executable(examples_stan examples_stan.cpp) target_link_libraries(examples_stan PRIVATE Eigen3::Eigen nuts::nuts BridgeStan::BridgeStan) target_compile_options(examples_stan PRIVATE -Wall) + + + FetchContent_Declare( + cli11 + GIT_REPOSITORY https://github.com/CLIUtils/CLI11.git + GIT_TAG v2.5.0 + ) + + FetchContent_MakeAvailable(cli11) + + add_executable(stan_cli stan_cli.cpp) + target_link_libraries(stan_cli PRIVATE Eigen3::Eigen nuts::nuts BridgeStan::BridgeStan CLI11::CLI11) + target_compile_options(stan_cli PRIVATE -Wall) endif() diff --git a/examples/stan_cli.cpp b/examples/stan_cli.cpp new file mode 100644 index 0000000..e5e5170 --- /dev/null +++ b/examples/stan_cli.cpp @@ -0,0 +1,288 @@ +#include +#include +#include + +#include "load_stan.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +using Vector = Eigen::Matrix; +using Matrix = Eigen::Matrix; + +static void summarize(const std::vector names, + const Matrix& draws) { + auto N = draws.cols(); + auto D = draws.rows(); + for (auto d = 0; d < D; ++d) { + if (d > 3 && d < D - 3) { + if (d == 4) { + std::cout << "... elided " << (D - 6) << " rows ..." << std::endl; + } + continue; + } + auto mean = draws.row(d).mean(); + auto var = (draws.row(d).array() - mean).square().sum() / (N - 1); + auto stddev = std::sqrt(var); + std::cout << names[d] << ": mean = " << mean << ", stddev = " << stddev + << "\n"; + } +} + +static void write_draws(const std::string& filename, + const std::vector& names, + const Matrix& draws) { + if (filename.empty()) { + return; + } + std::ofstream out(filename); + if (!out) { + std::cerr << "Failed to open output file: " << filename << std::endl; + return; + } + + for (size_t i = 0; i < names.size(); ++i) { + if (i > 0) { + out << ","; + } + out << names[i]; + } + out << "\n"; + + auto EigenCommaFormat = + Eigen::IOFormat(12, Eigen::DontAlignCols, ",", "\n", "", "", "", ""); + + out << draws.transpose().format(EigenCommaFormat); + out.close(); +} + +template +Matrix run_walnuts(DynamicStanModel& model, RNG& rng, const Vector& theta_init, + int64_t warmup, int64_t samples, double init_count, + double mass_iteration_offset, double additive_smoothing, + double step_size_init, double accept_rate_target, + double step_iteration_offset, double learning_rate, + double decay_rate, double max_error, int64_t max_nuts_depth, + int64_t max_step_depth) { + double logp_time = 0.0; + int logp_count = 0; + auto global_start = std::chrono::high_resolution_clock::now(); + + auto end_timing = [&]() { + auto global_end = std::chrono::high_resolution_clock::now(); + auto global_total_time = + std::chrono::duration(global_end - global_start).count(); + std::cout << " total time: " << global_total_time << "s" << std::endl; + std::cout << "logp_grad time: " << logp_time << "s" << std::endl; + std::cout << "logp_grad fraction: " << logp_time / global_total_time + << std::endl; + std::cout << " logp_grad calls: " << logp_count << std::endl; + std::cout << " time per call: " << logp_time / logp_count << "s" + << std::endl; + std::cout << std::endl; + }; + + Eigen::VectorXd mass_init = Eigen::VectorXd::Ones(theta_init.size()); + + nuts::MassAdaptConfig mass_cfg(mass_init, init_count, mass_iteration_offset, + additive_smoothing); + + nuts::StepAdaptConfig step_cfg(step_size_init, accept_rate_target, + step_iteration_offset, learning_rate, + decay_rate); + nuts::WalnutsConfig walnuts_cfg(max_error, max_nuts_depth, max_step_depth); + + std::cout << "Running Adaptive WALNUTS" + << "; D = " << theta_init.size() << "; W = " << warmup + << "; N = " << samples << "; step_size_init = " << step_size_init + << "; max_nuts_depth = " << max_nuts_depth + << "; max_error = " << max_error << std::endl; + + auto logp = [&](auto&&... args) { + auto start = std::chrono::high_resolution_clock::now(); + + model.logp_grad(args...); + + auto end = std::chrono::high_resolution_clock::now(); + logp_time += std::chrono::duration(end - start).count(); + ++logp_count; + }; + nuts::AdaptiveWalnuts walnuts(rng, logp, theta_init, mass_cfg, step_cfg, + walnuts_cfg); + + for (auto w = 0; w < warmup; ++w) { + walnuts(); + } + + end_timing(); + + // N post-warmup draws + auto sampler = walnuts.sampler(); // freeze tuning + std::cout << "Adaptation completed." << std::endl; + std::cout << "Macro step size = " << sampler.macro_step_size() << std::endl; + std::cout << "Mass matrix diagonal = [" + << sampler.inverse_mass_matrix_diagonal() << "]" << std::endl; + + Matrix draws(model.constrained_dimensions(), samples); + + logp_time = 0.0; + logp_count = 0; + global_start = std::chrono::high_resolution_clock::now(); + + for (auto n = 0; n < samples; ++n) { + model.constrain_draw(sampler(), draws.col(n)); + } + + end_timing(); + + return draws; +} + +template +Vector initialize(DynamicStanModel& model, RNG& rng, double init_range, + int64_t max_tries = 100) { + int D = model.unconstrained_dimensions(); + std::uniform_real_distribution initial(-init_range, init_range); + Vector theta_init(D); + + Vector grad(D); + double logp = 0.0; + + for (auto _ = 0; _ < max_tries; ++_) { + for (auto i = 0; i < D; ++i) { + theta_init(i) = initial(rng); + } + + model.logp_grad(theta_init, logp, grad); + if (std::isfinite(logp) && grad.allFinite()) { + // if the log density and gradient are finite, we can use this + // as the initial point + std::cout << "Initialized at [" << theta_init.transpose() << "]" + << std::endl; + return theta_init; + } + } + + throw std::runtime_error("Failed to initialize the model after " + + std::to_string(max_tries) + " tries."); +} + +int main(int argc, char** argv) { + srand(std::chrono::system_clock::now().time_since_epoch().count()); + unsigned int seed = rand(); + int64_t warmup = 1000; + int64_t samples = 1000; + int64_t max_nuts_depth = 10; + int64_t max_step_depth = 8; + double max_error = 0.5; + double init = 2.0; + double init_count = 1.1; + double mass_iteration_offset = 1.1; + double additive_smoothing = 0.1; + double step_size_init = 0.5; + double accept_rate_target = 2.0 / 3.0; + double step_iteration_offset = 2.0; + double learning_rate = 0.95; + double decay_rate = 0.05; + + std::string lib; + std::string data; + std::string output_file; + + // parse from command line with CLI11 + { + CLI::App app{"Run WALNUTs on a Stan model"}; + + app.add_option("--seed", seed, "Random seed")->default_val(seed); + + app.add_option("--warmup", warmup, "Number of warmup iterations") + ->default_val(warmup); + + app.add_option("--samples", samples, "Number of samples to draw") + ->default_val(samples); + + app.add_option("--max-depth", max_nuts_depth, + "Maximum depth for NUTS trajectory doublings") + ->default_val(max_nuts_depth); + + app.add_option("--max-step-depth", max_step_depth, + "Maximum depth for the step size adaptation") + ->default_val(max_step_depth); + + app.add_option("--max-error", max_error, + "Maximum error allowed in joint densities") + ->default_val(max_error); + + app.add_option("--init", init, + "Range [-init,init] for the parameters initial values") + ->default_val(init); + + app.add_option("--mass-init-count", init_count, + "Initial count for the mass matrix adaptation") + ->default_val(init_count); + + app.add_option("--mass-iteration-offset", mass_iteration_offset, + "Offset for the mass matrix adaptation iterations") + ->default_val(mass_iteration_offset); + + app.add_option("--mass-additive-smoothing", additive_smoothing, + "Additive smoothing for the mass matrix adaptation") + ->default_val(additive_smoothing); + + app.add_option("--step-size-init", step_size_init, + "Initial step size for the step size adaptation") + ->default_val(step_size_init); + + app.add_option("--step-accept-rate-target", accept_rate_target, + "Target acceptance rate for the step size adaptation") + ->default_val(accept_rate_target); + + app.add_option("--step-iteration-offset", step_iteration_offset, + "Offset for the step size adaptation iterations") + ->default_val(step_iteration_offset); + + app.add_option("--step-learning-rate", learning_rate, + "Learning rate for the step size adaptation") + ->default_val(learning_rate); + + app.add_option("--step-decay-rate", decay_rate, + "Decay rate for the step size adaptation") + ->default_val(decay_rate); + + app.add_option("model", lib, "Path to the Stan model library") + ->required() + ->check(CLI::ExistingFile); + + app.add_option("data", data, "Path to the Stan model data (optional)") + ->check(CLI::ExistingFile); + + app.add_option("--output", output_file, "Output file for the draws") + ->check(CLI::NonexistentPath); + + CLI11_PARSE(app, argc, argv); + } + + DynamicStanModel model(lib.c_str(), data.c_str(), seed); + + std::mt19937 rng(seed); + + Vector theta_init = initialize(model, rng, init); + + Matrix draws = + run_walnuts(model, rng, theta_init, warmup, samples, init_count, + mass_iteration_offset, additive_smoothing, step_size_init, + accept_rate_target, step_iteration_offset, learning_rate, + decay_rate, max_error, max_nuts_depth, max_step_depth); + + auto names = model.param_names(); + summarize(names, draws); + write_draws(output_file, names, draws); + + return 0; +} From 7fc82a0b82cdeb6e20bb3f57209b6ddb939627bf Mon Sep 17 00:00:00 2001 From: Brian Ward Date: Wed, 6 Aug 2025 12:10:18 -0400 Subject: [PATCH 4/7] Fix up readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8589e1d..6258df7 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ For example, to build and run the example: ```bash cmake --build . --target examples -./examples +./examples/examples ``` From 91ccd286a01727b703ce1b0c408fbe38e95410da Mon Sep 17 00:00:00 2001 From: Brian Ward Date: Tue, 2 Sep 2025 10:25:09 -0400 Subject: [PATCH 5/7] Workaround for crash on exit --- examples/load_stan.hpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/load_stan.hpp b/examples/load_stan.hpp index 61101bf..93c260f 100644 --- a/examples/load_stan.hpp +++ b/examples/load_stan.hpp @@ -34,21 +34,23 @@ static char* dlerror() { struct dlclose_deleter { void operator()(void* handle) const { - if (handle) { - dlclose(handle); - } + // TODO: Crashes on some systems, see + // https://github.com/flatironinstitute/walnuts/pull/25#discussion_r2298576937 + // if (handle) { + // dlclose(handle); + // } } }; using dynamic_library = std::unique_ptr; inline dynamic_library dlopen_safe(const char* path) { - auto handle = dlopen(path, RTLD_NOW); + auto handle = dlopen(path, RTLD_NOW | RTLD_NODELETE); if (!handle) { throw std::runtime_error(std::string("Error loading library '") + path + "': " + dlerror()); } - return std::unique_ptr(handle); + return dynamic_library(handle); } template From 7b49bfc6438bfc0381a6434cadcbf2f1bf94f498 Mon Sep 17 00:00:00 2001 From: Brian Ward Date: Wed, 3 Sep 2025 12:52:50 -0400 Subject: [PATCH 6/7] Take defaults and checks from #25 --- examples/stan_cli.cpp | 57 +++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/examples/stan_cli.cpp b/examples/stan_cli.cpp index e5e5170..ef07126 100644 --- a/examples/stan_cli.cpp +++ b/examples/stan_cli.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -176,19 +177,19 @@ Vector initialize(DynamicStanModel& model, RNG& rng, double init_range, int main(int argc, char** argv) { srand(std::chrono::system_clock::now().time_since_epoch().count()); unsigned int seed = rand(); - int64_t warmup = 1000; - int64_t samples = 1000; + int64_t warmup = 128; + int64_t samples = 128; int64_t max_nuts_depth = 10; int64_t max_step_depth = 8; double max_error = 0.5; double init = 2.0; double init_count = 1.1; double mass_iteration_offset = 1.1; - double additive_smoothing = 0.1; - double step_size_init = 0.5; - double accept_rate_target = 2.0 / 3.0; - double step_iteration_offset = 2.0; - double learning_rate = 0.95; + double additive_smoothing = 1e-5; + double step_size_init = 1.0; + double accept_rate_target = 0.8; + double step_iteration_offset = 5.0; + double learning_rate = 1.5; double decay_rate = 0.05; std::string lib; @@ -202,58 +203,72 @@ int main(int argc, char** argv) { app.add_option("--seed", seed, "Random seed")->default_val(seed); app.add_option("--warmup", warmup, "Number of warmup iterations") - ->default_val(warmup); + ->default_val(warmup) + ->check(CLI::NonNegativeNumber); app.add_option("--samples", samples, "Number of samples to draw") - ->default_val(samples); + ->default_val(samples) + ->check(CLI::PositiveNumber); app.add_option("--max-depth", max_nuts_depth, "Maximum depth for NUTS trajectory doublings") - ->default_val(max_nuts_depth); + ->default_val(max_nuts_depth) + ->check(CLI::PositiveNumber); app.add_option("--max-step-depth", max_step_depth, "Maximum depth for the step size adaptation") - ->default_val(max_step_depth); + ->default_val(max_step_depth) + ->check(CLI::PositiveNumber); app.add_option("--max-error", max_error, "Maximum error allowed in joint densities") - ->default_val(max_error); + ->default_val(max_error) + ->check(CLI::PositiveNumber); app.add_option("--init", init, "Range [-init,init] for the parameters initial values") - ->default_val(init); + ->default_val(init) + ->check(CLI::NonNegativeNumber); app.add_option("--mass-init-count", init_count, "Initial count for the mass matrix adaptation") - ->default_val(init_count); + ->default_val(init_count) + ->check(CLI::Range(1.0, std::numeric_limits::max())); app.add_option("--mass-iteration-offset", mass_iteration_offset, "Offset for the mass matrix adaptation iterations") - ->default_val(mass_iteration_offset); + ->default_val(mass_iteration_offset) + ->check(CLI::Range(1.0, std::numeric_limits::max())); app.add_option("--mass-additive-smoothing", additive_smoothing, "Additive smoothing for the mass matrix adaptation") - ->default_val(additive_smoothing); + ->default_val(additive_smoothing) + ->check(CLI::PositiveNumber); app.add_option("--step-size-init", step_size_init, "Initial step size for the step size adaptation") - ->default_val(step_size_init); + ->default_val(step_size_init) + ->check(CLI::PositiveNumber); app.add_option("--step-accept-rate-target", accept_rate_target, "Target acceptance rate for the step size adaptation") - ->default_val(accept_rate_target); + ->default_val(accept_rate_target) + ->check(CLI::Range(std::numeric_limits::min(), 1.0)); app.add_option("--step-iteration-offset", step_iteration_offset, "Offset for the step size adaptation iterations") - ->default_val(step_iteration_offset); + ->default_val(step_iteration_offset) + ->check(CLI::Range(1.0, std::numeric_limits::max())); app.add_option("--step-learning-rate", learning_rate, "Learning rate for the step size adaptation") - ->default_val(learning_rate); + ->default_val(learning_rate) + ->check(CLI::PositiveNumber); app.add_option("--step-decay-rate", decay_rate, "Decay rate for the step size adaptation") - ->default_val(decay_rate); + ->default_val(decay_rate) + ->check(CLI::PositiveNumber); app.add_option("model", lib, "Path to the Stan model library") ->required() From 368312b1074507e77010bcc9cf8de8b3b96e1e14 Mon Sep 17 00:00:00 2001 From: Brian Ward Date: Wed, 3 Sep 2025 14:10:01 -0400 Subject: [PATCH 7/7] Copy trick from cli11 to avoid msvc macro collision --- examples/stan_cli.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/stan_cli.cpp b/examples/stan_cli.cpp index ef07126..9b4e1f9 100644 --- a/examples/stan_cli.cpp +++ b/examples/stan_cli.cpp @@ -233,12 +233,12 @@ int main(int argc, char** argv) { app.add_option("--mass-init-count", init_count, "Initial count for the mass matrix adaptation") ->default_val(init_count) - ->check(CLI::Range(1.0, std::numeric_limits::max())); + ->check(CLI::Range(1.0, (std::numeric_limits::max)())); app.add_option("--mass-iteration-offset", mass_iteration_offset, "Offset for the mass matrix adaptation iterations") ->default_val(mass_iteration_offset) - ->check(CLI::Range(1.0, std::numeric_limits::max())); + ->check(CLI::Range(1.0, (std::numeric_limits::max)())); app.add_option("--mass-additive-smoothing", additive_smoothing, "Additive smoothing for the mass matrix adaptation") @@ -253,12 +253,12 @@ int main(int argc, char** argv) { app.add_option("--step-accept-rate-target", accept_rate_target, "Target acceptance rate for the step size adaptation") ->default_val(accept_rate_target) - ->check(CLI::Range(std::numeric_limits::min(), 1.0)); + ->check(CLI::Range((std::numeric_limits::min)(), 1.0)); app.add_option("--step-iteration-offset", step_iteration_offset, "Offset for the step size adaptation iterations") ->default_val(step_iteration_offset) - ->check(CLI::Range(1.0, std::numeric_limits::max())); + ->check(CLI::Range(1.0, (std::numeric_limits::max)())); app.add_option("--step-learning-rate", learning_rate, "Learning rate for the step size adaptation")