diff --git a/ScannerBit/include/gambit/ScannerBit/base_prior.hpp b/ScannerBit/include/gambit/ScannerBit/base_prior.hpp index 72b7557a16..0893a364ca 100644 --- a/ScannerBit/include/gambit/ScannerBit/base_prior.hpp +++ b/ScannerBit/include/gambit/ScannerBit/base_prior.hpp @@ -42,7 +42,7 @@ namespace Gambit { /** * @brief Abstract base class for priors */ - class BasePrior + class BasePrior { private: unsigned int param_size; @@ -67,13 +67,13 @@ namespace Gambit { virtual void transform(hyper_cube_ref unit, std::unordered_map &physical) const = 0; /** @overload in place STL containers */ - void transform(const std::vector &unit, std::unordered_map &physical) const + void transform(const std::vector &unit, std::unordered_map &physical) const { transform(map_vector(const_cast(&unit[0]), unit.size()), physical); } /** @overload return STL containers */ - std::unordered_map transform(const std::vector &unit) const + std::unordered_map transform(const std::vector &unit) const { std::unordered_map physical; transform(unit, physical); @@ -84,13 +84,13 @@ namespace Gambit { virtual void inverse_transform(const std::unordered_map &physical, hyper_cube_ref unit) const = 0; /** @overload in place STL containers */ - void inverse_transform(const std::unordered_map &physical, std::vector &unit) const + void inverse_transform(const std::unordered_map &physical, std::vector &unit) const { inverse_transform(physical, map_vector(const_cast(&unit[0]), unit.size())); } /** @overload return STL containers */ - std::vector inverse_transform(const std::unordered_map &physical) const + std::vector inverse_transform(const std::unordered_map &physical) const { std::vector unit(param_size); inverse_transform(physical, unit); @@ -102,6 +102,8 @@ namespace Gambit { virtual std::vector getShownParameters() const { return param_names; } + virtual std::vector getSetParameters() const { return param_names; } + inline unsigned int size() const { return param_size; } inline void setSize(const unsigned int size) { param_size = size; } @@ -112,7 +114,7 @@ namespace Gambit { }; } // namespace Priors - + } // namespace Gambit #endif // __BASE_PRIORS_HPP__ diff --git a/ScannerBit/include/gambit/ScannerBit/priors/composite.hpp b/ScannerBit/include/gambit/ScannerBit/priors/composite.hpp index e9f38bdb29..0befb9f9cf 100644 --- a/ScannerBit/include/gambit/ScannerBit/priors/composite.hpp +++ b/ScannerBit/include/gambit/ScannerBit/priors/composite.hpp @@ -4,12 +4,12 @@ /// /// Combine several priors to a prior for /// e.g. an entire model -/// +/// /// /// ********************************************* /// /// Authors (add name and date if you modify): -/// +/// /// \author Ben Farmer /// (benjamin.farmer@monash.edu.au) /// \date 2013 Dec @@ -36,9 +36,9 @@ #include "gambit/ScannerBit/scanner_utils.hpp" -namespace Gambit +namespace Gambit { - namespace Priors + namespace Priors { /// Special "build-a-prior" class /// This is the class to use for setting simple 1D priors (from the library above) on individual parameters. @@ -47,32 +47,35 @@ namespace Gambit class CompositePrior : public BasePrior { - + private: // References to component prior objects std::vector my_subpriors; std::vector shown_param_names; - + std::set set_param_names; + public: - + // Constructors defined in composite.cpp CompositePrior(const Options &model_options, const Options &prior_options); - + CompositePrior(const std::vector ¶ms, const Options &options); - - double log_prior_density(const std::unordered_map &physical) const override + + double log_prior_density(const std::unordered_map &physical) const override { double log_pdf_density = 0.0; for (auto it = my_subpriors.begin(), end = my_subpriors.end(); it != end; ++it) { log_pdf_density += (*it)->log_prior_density(physical); } - + return log_pdf_density; } - + inline std::vector getShownParameters() const override { return shown_param_names; } - + + inline std::vector getSetParameters() const override { return std::vector(set_param_names.begin(), set_param_names.end()); } + // Transformation from unit hypercube to physical parameters void transform(hyper_cube_ref unitPars, std::unordered_map &outputMap) const override { @@ -108,7 +111,7 @@ namespace Gambit auto round_trip = physical; transform(unit, round_trip); const double rtol = 1e-4; - for (const auto &s : physical) + for (const auto &s : physical) { const double a = round_trip.at(s.first); const double b = s.second; @@ -119,19 +122,19 @@ namespace Gambit } } } - + //~CompositePrior() noexcept ~CompositePrior() { // Need to destroy all the prior objects that we created using 'new' for (auto it = my_subpriors.begin(), end = my_subpriors.end(); it != end; it++) - { + { // Delete prior object delete *it; } - } + } }; - + LOAD_PRIOR(composite, CompositePrior) } // end namespace Priors } // end namespace Gambit diff --git a/ScannerBit/include/gambit/ScannerBit/py_module_scan.hpp b/ScannerBit/include/gambit/ScannerBit/py_module_scan.hpp index cd932d653f..34ce93b286 100644 --- a/ScannerBit/include/gambit/ScannerBit/py_module_scan.hpp +++ b/ScannerBit/include/gambit/ScannerBit/py_module_scan.hpp @@ -862,6 +862,12 @@ PYBIND11_EMBEDDED_MODULE(scanner_plugin, m) return names; }) + .def_property_readonly_static("set_parameter_names", [](py::object) + { + static py::list names = scanner_base::to_list(get_prior().getSetParameters()); + + return names; + }) .def_property_readonly_static("mpi_rank", [](py::object) { static int my_rank = scanner_base::rank(); diff --git a/ScannerBit/include/gambit/ScannerBit/scanners/diver_1.0.5/diver.hpp b/ScannerBit/include/gambit/ScannerBit/scanners/diver_1.3.0/diver.hpp similarity index 57% rename from ScannerBit/include/gambit/ScannerBit/scanners/diver_1.0.5/diver.hpp rename to ScannerBit/include/gambit/ScannerBit/scanners/diver_1.3.0/diver.hpp index ccd47b549a..ec7b1a83e4 100644 --- a/ScannerBit/include/gambit/ScannerBit/scanners/diver_1.0.5/diver.hpp +++ b/ScannerBit/include/gambit/ScannerBit/scanners/diver_1.3.0/diver.hpp @@ -2,7 +2,7 @@ // ********************************************* /// \file /// -/// ScannerBit interface to Diver 1.0.5 +/// ScannerBit interface to Diver 1.3.0 /// /// Header file /// @@ -11,26 +11,25 @@ /// Authors (add name and date if you modify): /// /// \author Pat Scott -/// (p.scott@imperial.ac.uk) -/// \date 2019 Dec +/// (patrickcolinscott@gmail.com) +/// \date 2025 Apr /// /// ********************************************* -#ifndef __diver_hpp__ -#define __diver_hpp__ +#pragma once #include "gambit/ScannerBit/scanner_plugin.hpp" // C++ prototype of the main run_de function for Diver. -extern "C" void cdiver(double (*)(double[], const int, int&, bool&, const bool, void*&), int, const double[], const double[], - const char[], int, int, const int[], bool, const int, const int, int, int, const double[], double, - double, bool, bool, int, bool, bool, double, int, bool, bool, double(*)(const double[], const int, void*&), - double, double, int, bool, bool, int, bool, int, double, int, void*&, int); +extern "C" double cdiver(double (*)(double[], const int, int&, bool&, const bool, void*&), int, const double[], const double[], + const char[], int, double[], double[], int, const int[], bool, int, int, int, const double[], double, double, bool, + bool, int, bool, bool, double, int, bool, int, bool, bool, bool, bool, int, int, const double[], bool, int, double, int, + void*&, int); namespace Gambit { - namespace Diver_1_0_5 + namespace Diver_1_3_0 { /// Structure for passing likelihood and printer data through Diver to the objective function. @@ -46,5 +45,3 @@ namespace Gambit } } - -#endif // #defined __diver_hpp__ diff --git a/ScannerBit/src/priors/composite.cpp b/ScannerBit/src/priors/composite.cpp index bc1927a531..c4846591b8 100644 --- a/ScannerBit/src/priors/composite.cpp +++ b/ScannerBit/src/priors/composite.cpp @@ -3,12 +3,12 @@ /// \file /// /// Prior object construction routines -/// +/// /// /// ********************************************* /// /// Authors (add name and date if you modify): -/// +/// /// \author Ben Farmer /// (benjamin.farmer@monash.edu.au) /// \date 2013 Dec @@ -29,37 +29,37 @@ #include "gambit/ScannerBit/priors_rollcall.hpp" #include "gambit/ScannerBit/scanner_utils.hpp" -namespace Gambit +namespace Gambit { // All priors are transformations which "stretch" one or more random variates // sampled uniformly from the interval [0,1] (or higher dim. equivalent) into // a sample from a different distribution. - + // All priors will be used by pointers to the base class "BasePrior", so they // must inherit from this class. Their constructors can be used to set up - // parameters of the transformation they perform, which should itself be + // parameters of the transformation they perform, which should itself be // actioned by the "transform" member function - + // Note that before the transformation by these priors, the random number // generation is totally symmetric in all parameters (this is my current // assumption, may need to relax it to accommodate some fancy scanner) // So the way the prior transformation is defined is what really defines which // parameter in the hypercube is which physical parameter. - - // However, this order has to be the order expected by the scanner wrapper of + + // However, this order has to be the order expected by the scanner wrapper of // the loglikelihood function (see ScannerBit/lib/multinest.cpp for example). // Parameter names are provided along with this function so that we can // match them up in the prior correctly. The idea is that the constructors // for the prior objects should be called in such a way as to match the // required parameter order. - - namespace Priors + + namespace Priors { std::vector expand_dots(const std::vector ¶m_names_in) { std::vector param_names = param_names_in; - + for (int i = 0, end = param_names.size(); i < end; i++) { if (param_names[i].find("...") != std::string::npos) @@ -73,20 +73,20 @@ namespace Gambit { p_it = param_names.erase(p_it); std::vector temps; - + for (int j = 0; j < N; j++) { std::stringstream ss; ss << j; temps.push_back(prefix + ss.str()); } - + param_names.insert(p_it, temps.begin(), temps.end()); i += N - 1; } } } - + return param_names; } /// Special "build-a-prior" classi @@ -94,36 +94,36 @@ namespace Gambit // This is the class to use for setting simple 1D priors (from the library above) on individual parameters. // It also allows for any combination of MD priors to be set on any combination of subspaces of // the full prior. - + // Constructor CompositePrior::CompositePrior(const Options &model_options, const Options &prior_options) - { + { std::map sameMap; std::unordered_map> sameMapOptions; std::vector phantomPriors; std::set needSet; - + // Get model parameters from the inifile std::vector modelNames = model_options.getNames(); std::sort(modelNames.begin(), modelNames.end()); - + //main loop to enter in parameter values for (auto mod_it = modelNames.begin(), mod_end = modelNames.end(); mod_it != mod_end; ++mod_it) {//loop over iniFile models std::string &mod = *mod_it; std::vector parameterNames = model_options.getNames(mod); std::sort(parameterNames.begin(), parameterNames.end()); - + int default_N = 0, default_i = 0; bool isDefault = false; std::string default_prefix; std::string::size_type par_pos; - + for (auto par_it = parameterNames.begin(), par_end = parameterNames.end(); par_it != par_end; par_it++) {//loop over iniFile parameters Options par_options; std::string par_name; - + par_pos = par_it->find("..."); if (!isDefault && par_pos != std::string::npos) { @@ -136,7 +136,7 @@ namespace Gambit default_i = 0; } } - + if (isDefault) { std::stringstream ss; @@ -147,9 +147,9 @@ namespace Gambit { par_name = *par_it; } - + param_names.push_back(mod + std::string("::") + par_name); - + if ((model_options.getNode(mod, *par_it).IsScalar() && (model_options.getValue(mod, *par_it) == "in_priors")) || model_options.getNode(mod, *par_it).IsNull()) { std::string joined_parname = mod + std::string("::") + par_name; @@ -163,7 +163,7 @@ namespace Gambit else { par_options = Options(model_options.getNode(mod, *par_it)); - + if (par_options.hasKey("same_as")) { std::string connectedName = par_options.getValue("same_as"); @@ -172,52 +172,52 @@ namespace Gambit { connectedName += std::string("::") + par_name; } - + sameMap[mod + std::string("::") + par_name] = connectedName; - + auto opt = std::pair(1.0, 0.0); if (par_options.hasKey("scale")) { opt.first = par_options.getValue("scale"); } - + if (par_options.hasKey("shift")) { opt.second = par_options.getValue("shift"); } - + sameMapOptions[mod + std::string("::") + par_name] = opt; } else if (par_options.hasKey("fixed_value")) { phantomPriors.push_back(new FixedPrior(mod + std::string("::") + par_name, par_options.getNode("fixed_value"))); } - else + else { std::string joined_parname = mod + std::string("::") + par_name; - + if (par_options.hasKey("prior_type")) { Options options = par_options.getOptions(); std::string priortype = par_options.getValue("prior_type"); - + if(priortype == "same_as") { if (options.hasKey("same_as")) { sameMap[joined_parname] = options.getValue("same_as"); - + auto opt = std::pair(1.0, 0.0); if (par_options.hasKey("scale")) { opt.first = par_options.getValue("scale"); } - + if (par_options.hasKey("shift")) { opt.second = par_options.getValue("shift"); } - + sameMapOptions[joined_parname] = opt; } else @@ -235,7 +235,7 @@ namespace Gambit else { BasePrior *new_prior = prior_creators.at(priortype)(std::vector(1, joined_parname),options); - + if (priortype == "fixed") { phantomPriors.push_back(new_prior); @@ -251,17 +251,17 @@ namespace Gambit else if (par_options.hasKey("range")) { shown_param_names.push_back(joined_parname); - + my_subpriors.push_back(new RangePrior1D(std::vector(1, joined_parname), par_options)); } - else + else { shown_param_names.push_back(joined_parname); needSet.insert(joined_parname); } } } - + if (isDefault && default_N > 0) { if (default_N > default_i) @@ -271,11 +271,11 @@ namespace Gambit } } } - + // Get the list of priors to build from the iniFile std::vector priorNames = prior_options.getNames(); std::sort(priorNames.begin(), priorNames.end()); - std::set paramSet(shown_param_names.begin(), shown_param_names.end()); + set_param_names = std::set(shown_param_names.begin(), shown_param_names.end()); for (auto priorname_it = priorNames.begin(), priorname_end = priorNames.end(); priorname_it != priorname_end; priorname_it++) { @@ -283,10 +283,10 @@ namespace Gambit if (prior_options.hasKey(priorname, "parameters") && prior_options.hasKey(priorname, "prior_type")) { auto params = expand_dots(prior_options.getValue>(priorname, "parameters")); - + for (auto par_it = params.begin(), par_end = params.end(); par_it != par_end; par_it++) { - if (paramSet.find(*par_it) == paramSet.end()) + if (set_param_names.find(*par_it) == set_param_names.end()) { scan_err << "Parameter " << *par_it << " requested by " << priorname << " is either not defined by the inifile, is fixed, or is the \"same as\" another parameter." << scan_end; } @@ -306,7 +306,7 @@ namespace Gambit auto options = prior_options.getOptions(priorname); auto priortype = prior_options.getValue(priorname, "prior_type"); - + if (prior_creators.find(priortype) == prior_creators.end()) { scan_err << "Prior '"<< priorname <<"' is of type '"<< priortype <<"', but no entry for this type exists in the factory function map.\n" << prior_creators.print() << scan_end; @@ -322,7 +322,7 @@ namespace Gambit std::find(shown_param_names.begin(), shown_param_names.end(), *par_it) ); }*/ - + //my_subpriors.push_back( prior_creators.at(priortype)(params,options) ); phantomPriors.push_back( prior_creators.at(priortype)(params,options) ); } @@ -356,10 +356,10 @@ namespace Gambit { BasePrior* new_prior = prior_creators.at(priortype)(params,options); my_subpriors.push_back( new_prior ); - + auto params = new_prior->getShownParameters(); shown_param_names.insert(shown_param_names.end(), params.begin(), params.end()); - + /*if (priortype == "composite") { auto composite_new_prior = static_cast(new_prior); @@ -379,7 +379,7 @@ namespace Gambit scan_err << "\"parameters\" and \"prior_type\" need to be defined for prior \"" << priorname << "\"" << scan_end; } } - + if (needSet.size() != 0) { scan_err << "Priors are not defined for the following parameters: ["; @@ -391,7 +391,7 @@ namespace Gambit } scan_err << "]" << scan_end; } - + std::map keyMap; std::string index, result; unsigned int reps; @@ -404,13 +404,13 @@ namespace Gambit { index = result; result = sameMap[index]; - + if (result == strMap->first) { scan_err << "Parameter " << strMap->first << " is \"same as\" itself." << scan_end; break; } - + if (reps > sameMap.size()) { scan_err << "Parameter's \"same as\"'s are loop in on each other." << scan_end; @@ -418,13 +418,13 @@ namespace Gambit } reps++; } - + if (keyMap.find(result) == keyMap.end()) keyMap[result] = strMap->first + std::string("+") + result; else keyMap[result] = strMap->first + std::string("+") + keyMap[result]; } - + for (auto str_it = shown_param_names.begin(), str_end = shown_param_names.end(); str_it != str_end; str_it++) { auto it = keyMap.find(*str_it); @@ -433,10 +433,10 @@ namespace Gambit *str_it = it->second; } } - + for (auto key_it = keyMap.begin(), key_end = keyMap.end(); key_it != key_end; key_it++) { - if (paramSet.find(key_it->first) == paramSet.end()) + if (set_param_names.find(key_it->first) == set_param_names.end()) { scan_err << "same_as: " << key_it->first << " is not defined in inifile." << scan_end; } @@ -445,44 +445,44 @@ namespace Gambit phantomPriors.push_back(new MultiPriors(key_it->second, sameMapOptions)); } } - + int param_size = 0; for (auto subprior = my_subpriors.begin(), prior_end = my_subpriors.end(); subprior != prior_end; subprior++) { param_size += (*subprior)->size(); } - + setSize(param_size); - + my_subpriors.insert(my_subpriors.end(), phantomPriors.begin(), phantomPriors.end()); - } - + } + CompositePrior::CompositePrior(const std::vector ¶ms_in, const Options &options_in) : BasePrior(params_in)//, shown_param_names(params_in) - { + { std::map sameMap; std::unordered_map> sameMapOptions; std::set needSet(params_in.begin(), params_in.end()); - std::set paramSet(params_in.begin(), params_in.end()); + set_param_names = std::set(params_in.begin(), params_in.end()); std::vector phantomPriors; auto priorNames = options_in.getNames(); std::sort(priorNames.begin(), priorNames.end()); - + for (auto priorname_it = priorNames.begin(), priorname_end = priorNames.end(); priorname_it != priorname_end; ++priorname_it) { std::string &priorname = *priorname_it; if (options_in.hasKey(priorname, "parameters") && options_in.hasKey(priorname, "prior_type")) { //auto params = options_in.getValue>(priorname, "parameters"); - + auto params = Gambit::Scanner::get_yaml_vector(options_in.getNode(priorname, "parameters")); - + for (auto par_it = params.begin(), par_end = params.end(); par_it != par_end; par_it++) { std::string &par = *par_it; - if (paramSet.find(par) == paramSet.end()) + if (set_param_names.find(par) == set_param_names.end()) { - scan_err << "Parameter " << par << " requested by " << priorname + scan_err << "Parameter " << par << " requested by " << priorname << " is either not defined by the inifile, is fixed, or is the \"same as\" another parameter." << scan_end; } else @@ -490,7 +490,7 @@ namespace Gambit auto find_it = needSet.find(par); if (find_it == needSet.end()) { - scan_err << "Parameter " << par << " requested by prior '"<< priorname + scan_err << "Parameter " << par << " requested by prior '"<< priorname <<"' is reserved by a different prior." << scan_end; } else @@ -502,10 +502,10 @@ namespace Gambit auto options = options_in.getOptions(priorname); auto priortype = options_in.getValue(priorname, "prior_type"); - + if (prior_creators.find(priortype) == prior_creators.end()) { - scan_err << "Prior '"<< priorname <<"' is of type '"<< priortype + scan_err << "Prior '"<< priorname <<"' is of type '"<< priortype <<"', but no entry for this type exists in the factory function map.\n" << prior_creators.print() << scan_end; } else @@ -519,7 +519,7 @@ namespace Gambit std::find(shown_param_names.begin(), shown_param_names.end(), *par_it) ); }*/ - + phantomPriors.push_back( prior_creators.at(priortype)(params,options) ); } else if (priortype == "same_as") @@ -544,10 +544,10 @@ namespace Gambit else { //my_subpriors.push_back( prior_creators.at(priortype)(params,options) ); - + BasePrior* new_prior = prior_creators.at(priortype)(params,options); my_subpriors.push_back( new_prior ); - + auto params = new_prior->getShownParameters(); shown_param_names.insert(shown_param_names.end(), params.begin(), params.end()); } @@ -558,7 +558,7 @@ namespace Gambit scan_err << "\"parameters\" and \"prior_type\" need to be defined for prior \"" << priorname << "\"" << scan_end; } } - + if (needSet.size() != 0) { scan_err << "Priors are not defined for the following parameters: ["; @@ -570,7 +570,7 @@ namespace Gambit } scan_err << "]" << scan_end; } - + std::map keyMap; std::string index, result; unsigned int reps; @@ -583,13 +583,13 @@ namespace Gambit { index = result; result = sameMap[index]; - + if (result == strMap_it->first) { scan_err << "Parameter " << strMap_it->first << " is \"same as\" itself." << scan_end; break; } - + if (reps > sameMap.size()) { scan_err << "Parameter's \"same as\"'s are loop in on each other." << scan_end; @@ -597,13 +597,13 @@ namespace Gambit } reps++; } - + if (keyMap.find(result) == keyMap.end()) keyMap[result] = strMap_it->first + std::string("+") + result; else keyMap[result] = strMap_it->first + std::string("+") + keyMap[result]; } - + for (auto str_it = shown_param_names.begin(), str_end = shown_param_names.end(); str_it != str_end; str_it++) { auto it = keyMap.find(*str_it); @@ -612,10 +612,10 @@ namespace Gambit *str_it = it->second; } } - + for (auto key_it = keyMap.begin(), key_end = keyMap.end(); key_it != key_end; key_it++) { - if (paramSet.find(key_it->first) == paramSet.end()) + if (set_param_names.find(key_it->first) == set_param_names.end()) { scan_err << "same_as: " << key_it->first << " is not defined in inifile." << scan_end; } @@ -624,15 +624,15 @@ namespace Gambit phantomPriors.push_back(new MultiPriors(key_it->second, sameMapOptions)); } } - + int param_size = 0; for (auto subprior = my_subpriors.begin(), subprior_end = my_subpriors.end(); subprior != subprior_end; subprior++) { param_size += (*subprior)->size(); } - + setSize(param_size); - + my_subpriors.insert(my_subpriors.end(), phantomPriors.begin(), phantomPriors.end()); } } // end namespace Priors diff --git a/ScannerBit/src/scanners/diver_1.0.5/diver.cpp b/ScannerBit/src/scanners/diver_1.3.0/diver.cpp similarity index 65% rename from ScannerBit/src/scanners/diver_1.0.5/diver.cpp rename to ScannerBit/src/scanners/diver_1.3.0/diver.cpp index 73886d1477..1547f22a8b 100755 --- a/ScannerBit/src/scanners/diver_1.0.5/diver.cpp +++ b/ScannerBit/src/scanners/diver_1.3.0/diver.cpp @@ -2,15 +2,15 @@ // ********************************************* /// \file /// -/// ScannerBit interface to Diver 1.0.5 +/// ScannerBit interface to Diver 1.3.0 /// /// ********************************************* /// /// Authors (add name and date if you modify): /// /// \author Pat Scott -/// (p.scott@imperial.ac.uk) -/// \date 2017 June, Nov +/// (patrickcolinscott@gmail.com) +/// \date 2025 Apr /// /// ********************************************* @@ -18,7 +18,7 @@ #include #include -#include "gambit/ScannerBit/scanners/diver_1.0.5/diver.hpp" +#include "gambit/ScannerBit/scanners/diver_1.3.0/diver.hpp" #include "gambit/Utils/yaml_options.hpp" #include "gambit/Utils/util_types.hpp" #include "gambit/Utils/util_functions.hpp" @@ -28,12 +28,12 @@ /// Interface to ScannerBit /// ================================================= -scanner_plugin(diver, version(1, 0, 5)) +scanner_plugin(diver, version(1, 3, 0)) { // Access Diver stuff and standard Gambit things using namespace Gambit; - using namespace Gambit::Diver_1_0_5; + using namespace Gambit::Diver_1_3_0; // Error thrown if the following entries are not present in the inifile reqd_inifile_entries("NP"); @@ -100,11 +100,10 @@ scanner_plugin(diver, version(1, 0, 5)) gl0 = -1.0 * (gl0 + offset); // Other Diver run parameters - int nPar = get_dimension(); // Dimensionality of the parameter space - int nDerived = 0; // Number of derived quantities to output (GAMBIT printers handle these). - int nDiscrete = get_inifile_value ("nDiscrete", 0); // Number of parameters that are to be treated as discrete + size_t nPar = get_dimension(); // Dimensionality of the parameter space + size_t nDerived = 0; // Number of derived quantities to output (GAMBIT printers handle these). + size_t nDiscrete = get_inifile_value ("nDiscrete", 0); // Number of parameters that are to be treated as discrete bool partitionDiscrete = get_inifile_value ("partitionDiscrete", false); // Split the population evenly amongst discrete parameters and evolve separately - int maxciv = get_inifile_value ("maxciv", 1); // Maximum number of civilisations int maxgen = get_inifile_value ("maxgen", 5000); // Maximum number of generations per civilisation int NP = get_inifile_value ("NP"); // Population size (individuals per generation) double Cr = get_inifile_value("Cr", 0.9); // Crossover factor @@ -117,18 +116,16 @@ scanner_plugin(diver, version(1, 0, 5)) double convthresh = get_inifile_value("convthresh", 1.e-3); // Threshold for gen-level convergence: smoothed fractional improvement in the mean population value int convsteps = get_inifile_value ("convsteps", 10); // Number of steps to smooth over when checking convergence bool removeDuplicates = get_inifile_value ("removeDuplicates", true); // Weed out duplicate vectors within a single generation - bool doBayesian = false; // Calculate approximate log evidence and posterior weightings - double maxNodePop = 1.9; // Population at which node is partitioned in binary space partitioning for posterior - double Ztolerance = 0.01; // Input tolerance in log-evidence int savecount = get_inifile_value ("savecount", 1); // Save progress every savecount generations - bool native_output = get_inifile_value ("full_native_output", true); // Output .raw file (Diver native sample output format) + bool disableIO = get_inifile_value ("disableIO", false); // Disable all IO (overrides outputRaw and outputSam if true) + bool outputRaw = get_inifile_value ("outputRaw", true); // Output .raw file (Diver native sample output format) + bool outputSam = get_inifile_value ("outputSam", true); // Output .sam file (rounded and derived parameter samples) int init_pop_strategy = get_inifile_value ("init_population_strategy", 2);// Initialisation strategy: 0=one shot, 1=n-shot, 2=n-shot with error if no valid vectors found. bool discard_unfit_points= get_inifile_value ("discard_unfit_points", false);// Recalculate any trial vector whose fitness is above max_acceptable_value int max_ini_attempts = get_inifile_value ("max_initialisation_attempts", 10000); // Maximum number of times to try to find a valid vector for each slot in the initial population. double max_acceptable_value= get_inifile_value("max_acceptable_value",0.9999*gl0); // Maximum function value to accept for the initial gen if init_population_strategy > 0, or any gen if discard_unfit_points=T. - int verbose = get_inifile_value ("verbosity", 0); // Output verbosity: 0=only error messages, 1=basic info, 2=civ-level info, 3+=population info + int verbose = get_inifile_value ("verbosity", 0); // Output verbosity: 0=only error messages, 1=basic info, 2+=population info int seed = get_inifile_value ("seed", -1); // Base seed for random number generation; non-positive means seed from the system clock - double (*prior)(const double[], const int, void*&) = NULL; // Pointer to prior function, only used if doBayesian = true. void* context = &data; // Pointer to GAMBIT likelihood function and printers, passed through to objective function. // Copy the contents of root to a char array. @@ -139,20 +136,75 @@ scanner_plugin(diver, version(1, 0, 5)) std::vector lowerbounds(nPar, 0.0); // Lower boundaries of parameter space to scan std::vector upperbounds(nPar, 1.0); // Upper boundaries of parameter space to scan + // Containers for returned best-fit parameters and derived quantities (not used) + std::vector bestFitParams(nPar); // Placeholder for returned parameters at best-fit point + double bestFitDerived[] = {0}; // Placeholder for returned derived quantities at best-fit point + // Scale factors std::vector Fvec = get_inifile_value >("F", initVector(0.7)); - int nF = Fvec.size(); // Size of the array indicating scale factors + size_t nF = Fvec.size(); // Size of the array indicating scale factors + + // Discrete parameters. TODO Needs to be set automatically somehow? Not yet sure how to deal with discrete parameters in GAMBIT. + std::vector discrete(nDiscrete, 0); // Indices of discrete parameters, Fortran style, i.e. starting at 1!! + + // Initial guesses. + size_t nGuesses = 0; + std::vector initial_guesses = {0}; + const YAML::Node initial_guesses_node = get_inifile_node("initial_guesses"); + if (initial_guesses_node) + { + // Make sure the parameter names and values are both present + if (!initial_guesses_node["parameters"] or !initial_guesses_node["values"]) + { + scan_err << "Diver \"initial_guesses\" option requires both \"parameters\" and \"values\"." << scan_end; + } + std::vector ig_parnames = initial_guesses_node["parameters"].as>(); + std::vector> ig_values = initial_guesses_node["values"].as>>(); + + // Make sure the parameter names all match up to ones being scanned. + const std::vector valid_parameters = data.likelihood_function->getPrior().getSetParameters(); + for (auto parname : ig_parnames) + { + if (not std::count(valid_parameters.begin(), valid_parameters.end(), parname)) + { + scan_err << "Parameter " << parname << " specified in \"initial_guesses\" is not one of the following being scanned over:" + << endl << " " << valid_parameters << scan_end; + } + } + + // Determine the total number of guesses, and therefore the size of the array that needs to be passed to Diver + nGuesses = ig_values.size(); + initial_guesses = std::vector(nPar*nGuesses); + + // Make sure the number of stated parameters matches the number of free ones in the scan + if (ig_parnames.size() != nPar) scan_err << "Initial guess \"parameters\" field contains " << ig_parnames.size() << " parameters, but the scan is over " << nPar << "." << scan_end; - // Discrete parameters - std::vector discrete(nDiscrete, 0); // Indices of discrete parameters, Fortran style, i.e. starting at 1!! - //TODO Needs to be set automatically somehow? Not yet sure how to deal with discrete parameters in GAMBIT. + // Convert each guess to the unit hypercube + for (size_t i = 0; i < nGuesses; i++) + { + const std::vector& guess = ig_values[i]; + // Make sure the number of guessed parameters matches the number of free ones in the scan + if (guess.size() != nPar) scan_err << "Initial guess contains " << guess.size() << " parameters; expected " << nPar << ".\n Guess: " << guess << scan_end; + // Construct the guess as a map from parameters to values + std::unordered_map parmap; + std::transform(ig_parnames.begin(), ig_parnames.end(), guess.begin(), std::inserter(parmap, parmap.end() ), std::make_pair); + // For each physical guess, save its correctly-ordered equivalent in the hypercube + size_t j = 0; + for (const double& par : data.likelihood_function->inverse_transform(parmap)) + { + // Initial guesses is read inside Diver as a C++ 2D array with first index the parameter, second the individual. + initial_guesses[j*nGuesses + i] = par; + j++; + } + } + } // Run Diver if (data.likelihood_function->getRank() == 0) cout << "Starting Diver run..." << std::endl; - cdiver(&objective, nPar, &lowerbounds[0], &upperbounds[0], &path[0], nDerived, nDiscrete, - &discrete[0], partitionDiscrete, maxciv, maxgen, NP, nF, &Fvec[0], Cr, lambda, current, - expon, bndry, jDE, lambdajDE, convthresh, convsteps, removeDuplicates, doBayesian, - prior, maxNodePop, Ztolerance, savecount, resume, native_output, init_pop_strategy, + cdiver(&objective, nPar, &lowerbounds[0], &upperbounds[0], &path[0], nDerived, &bestFitParams[0], + bestFitDerived, nDiscrete, &discrete[0], partitionDiscrete, maxgen, NP, nF, &Fvec[0], Cr, + lambda, current, expon, bndry, jDE, lambdajDE, convthresh, convsteps, removeDuplicates, + savecount, resume, disableIO, outputRaw, outputSam, init_pop_strategy, nGuesses, &initial_guesses[0], discard_unfit_points, max_ini_attempts, max_acceptable_value, seed, context, verbose); if (data.likelihood_function->getRank() == 0) cout << "Diver run finished!" << std::endl; return 0; @@ -168,7 +220,7 @@ scanner_plugin(diver, version(1, 0, 5)) namespace Gambit { - namespace Diver_1_0_5 + namespace Diver_1_3_0 { //Function to be minimized. Corresponds to -ln(Likelihood). Redirects to the target of context pointer. diff --git a/cmake/scanners.cmake b/cmake/scanners.cmake index c093dae453..4f632af721 100644 --- a/cmake/scanners.cmake +++ b/cmake/scanners.cmake @@ -117,6 +117,7 @@ if(NOT ditched_${name}_${ver}) endif() endif() # End if(NOT GAMBIT_LIGHT) +if(NOT GAMBIT_LIGHT) # Do not include this version in GAMBIT-light set(name "diver") set(ver "1.0.5") set(lib "libdiver") @@ -130,6 +131,33 @@ else() set(diverFFLAGS "${BACKEND_Fortran_FLAGS}") endif() check_ditch_status(${name} ${ver} ${dir}) +if(NOT ditched_${name}_${ver}) + ExternalProject_Add(${name}_${ver} + DOWNLOAD_DIR ${scanner_download} + DOWNLOAD_COMMAND ${DL_SCANNER} ${dl} ${md5} ${dir} ${name} ${ver} + SOURCE_DIR ${dir} + BUILD_IN_SOURCE 1 + CONFIGURE_COMMAND "" + BUILD_COMMAND ${CMAKE_MAKE_PROGRAM} ${lib}.so FF=${CMAKE_Fortran_COMPILER} MODULE=${FMODULE} FOPT=${diverFFLAGS} SO_LINK_FLAGS=${diverSO_LINK_FLAGS} + INSTALL_COMMAND "" + ) + add_extra_targets("scanner" ${name} ${ver} ${dir} ${dl} clean) +endif() +endif() # End if(NOT GAMBIT_LIGHT) + +set(name "diver") +set(ver "1.3.0") +set(lib "libdiver") +set(dl "https://github.com/diveropt/Diver/archive/refs/tags/v${ver}.tar.gz") +set(md5 "35255776f1f8f187e8b537cf5f47399a") +set(dir "${PROJECT_SOURCE_DIR}/ScannerBit/installed/${name}/${ver}") +set(diverSO_LINK_FLAGS "${CMAKE_Fortran_MPI_SO_LINK_FLAGS} -fopenmp") +if(MPI_Fortran_FOUND) + set(diverFFLAGS "${BACKEND_Fortran_FLAGS_PLUS_MPI}") +else() + set(diverFFLAGS "${BACKEND_Fortran_FLAGS}") +endif() +check_ditch_status(${name} ${ver} ${dir}) if(NOT ditched_${name}_${ver}) ExternalProject_Add(${name}_${ver} DOWNLOAD_DIR ${scanner_download} diff --git a/config/scanner_locations.yaml.default b/config/scanner_locations.yaml.default index b7e229de15..d31c6b8d76 100644 --- a/config/scanner_locations.yaml.default +++ b/config/scanner_locations.yaml.default @@ -36,6 +36,8 @@ diver: - lib: ./ScannerBit/installed/diver/1.0.4/lib/libdiver.so 1.0.5: - lib: ./ScannerBit/installed/diver/1.0.5/lib/libdiver.so + 1.3.0: + - lib: ./ScannerBit/installed/diver/1.3.0/lib/libdiver.so great: 1.0.0: diff --git a/yaml_files/gambit_light_example.yaml b/yaml_files/gambit_light_example.yaml index 77c724ec6a..c1eebbf68b 100644 --- a/yaml_files/gambit_light_example.yaml +++ b/yaml_files/gambit_light_example.yaml @@ -1,5 +1,5 @@ # ---------------------------------- -# GAMBIT_light configuration example +# GAMBIT_light configuration example # ---------------------------------- UserModel: @@ -14,7 +14,7 @@ UserModel: # prior_type: flat # range: [0.0, 5.0] - p3: + p3: name: param_name_3 # fixed_value: 3.0 @@ -22,16 +22,16 @@ UserModel: name: param_name_4 # same_as: UserModel::p1 - p5-p7: + p5-p7: name: param_name_ # GAMBIT will generate the names "param_name_5", "param_name_6", etc. # prior_type: flat # range: [-1.0, 1.0] -# Instead of specifying individual parameter priors above, -# a user-provided prior transform function can be used via -# the "UserPrior" section below. The user-defined prior -# function should take care of the prior transform +# Instead of specifying individual parameter priors above, +# a user-provided prior transform function can be used via +# the "UserPrior" section below. The user-defined prior +# function should take care of the prior transform # (from the unit hypercube) for all parameters in use. UserPrior: @@ -55,8 +55,8 @@ UserPrior: UserLogLikes: - # Note: - # If a loglike function expects all the UserModel parameters + # Note: + # If a loglike function expects all the UserModel parameters # as input, you can leave out the 'input' section (see below). py_user_loglike: @@ -108,7 +108,7 @@ UserLogLikes: # output: # - cpp_user_loglike_output_1 # - cpp_user_loglike_output_2 - # # - cpp_user_loglike_output_3 # We can comment out an outputs if we + # # - cpp_user_loglike_output_3 # We can comment out an outputs if we # # don't want to include it in the scan output # fortran_user_loglike: @@ -145,22 +145,22 @@ Printer: group: "/data" delete_file_on_restart: true disable_combine_routines: true - # Note: The hdf5_v1 printer writes one HDF5 file per MPI process and then combines these - # files at the end into a single HDF5 file. If the run output is very large, the combination + # Note: The hdf5_v1 printer writes one HDF5 file per MPI process and then combines these + # files at the end into a single HDF5 file. If the run output is very large, the combination # step at the end can take a long time, which may be impractical e.g. when running GAMBIT-light # on an HPC system with a job time limit. An alternative then is to use the option - # + # # disable_combine_routines: true - # + # # and "manually" combine the HDF5 files after the GAMBIT-light run. A script for doing this can # be found in Printers/scripts/hdf5_combine.py. Use it as follows: - # + # # python combine_hdf5.py ... - # + # # Example: - # + # # python path/to/Printers/scripts/combine_hdf5.py results.hdf5 data results.hdf5_temp_* - + Scanner: @@ -193,6 +193,13 @@ Scanner: max_initialisation_attempts: 10000 # Maximum number of times to try to find a valid vector for each slot in the initial population. verbosity: 0 # Output verbosity: 0=only error messages, 1=basic info, 2=civ-level info, 3+=population info seed: -1 # Base seed for random number generation; non-positive means seed from the system clock + initial_guesses: # Starting guesses for the parameter values -- use if you want to seed the scan with known good values. + parameters: [UserModel::p1, UserModel::p2, UserModel::p5, UserModel::p6, UserModel::p7] # Explains which parameter is which in the starting guesses. Be sure to use originals rather than parameters declared "same_as". + values: # The actual parameter values of the guesses + - [2, 2, 0.1, 0.1, 0.1] # A guess at the parameter values + - [2, 3, 0, 0, 0] # Another guess at the parameter values + - [2, 2, 0.1, -0.1, 0] # Yet another guess + polychord: plugin: polychord @@ -273,7 +280,7 @@ Scanner: scipy_basin_hopping: like: LogLike plugin: scipy_basin_hopping - # The run arguments below have been tested with scipy v1.9. + # The run arguments below have been tested with scipy v1.9. # Other versions might expect different arguments. run: # n_runs: 4 @@ -293,7 +300,7 @@ Scanner: scipy_differential_evolution: like: LogLike plugin: scipy_differential_evolution - # The run arguments below have been tested with scipy v1.9. + # The run arguments below have been tested with scipy v1.9. # Other versions might expect different arguments. run: # n_runs: 4 @@ -315,7 +322,7 @@ Scanner: scipy_direct: like: LogLike plugin: scipy_direct - # The run arguments below have been tested with scipy v1.9. + # The run arguments below have been tested with scipy v1.9. # Other versions might expect different arguments. run: # n_runs: 4 @@ -329,7 +336,7 @@ Scanner: scipy_dual_annealing: like: LogLike plugin: scipy_dual_annealing - # The run arguments below have been tested with scipy v1.9. + # The run arguments below have been tested with scipy v1.9. # Other versions might expect different arguments. run: # n_runs: 4 @@ -347,7 +354,7 @@ Scanner: scipy_shgo: like: LogLike plugin: scipy_shgo - # The run arguments below have been tested with scipy v1.9. + # The run arguments below have been tested with scipy v1.9. # Other versions might expect different arguments. run: split_param_space: @@ -377,7 +384,7 @@ Scanner: scipy_minimize: like: LogLike plugin: scipy_minimize - # The run arguments below have been tested with scipy v1.9. + # The run arguments below have been tested with scipy v1.9. # Other versions might expect different arguments. run: # n_runs: 5 @@ -402,7 +409,7 @@ Scanner: run: dlogz: 0.5 checkpoint_every: 60 - + dynamic_dynesty: like: LogLike plugin: dynamic_dynesty @@ -485,7 +492,7 @@ KeyValues: # An additional entry in the dataset and metadata, useful for identifying which # points correspond to a given scan in combined datasets. - # The default is for print_scanID: true, + # The default is for print_scanID: true, # and for it to print the date and time as an int of the form # scanID: HourMinuteSecondMillisecond. This can be overwritten to any integer. print_scanID: true