From 68df37918a952636267690b476aa56a964e95818 Mon Sep 17 00:00:00 2001 From: Pat Scott Date: Sat, 5 Apr 2025 23:04:47 +1000 Subject: [PATCH 1/7] Add interface for diver 1.3, including example of setting initial guesses in spartan.yaml new file: ScannerBit/include/gambit/ScannerBit/scanners/diver_1.3.0/diver.hpp new file: ScannerBit/src/scanners/diver_1.3.0/diver.cpp modified: cmake/scanners.cmake modified: config/scanner_locations.yaml.default --- .../ScannerBit/scanners/diver_1.3.0/diver.hpp | 47 ++++ ScannerBit/src/scanners/diver_1.3.0/diver.cpp | 241 ++++++++++++++++++ cmake/scanners.cmake | 26 ++ config/scanner_locations.yaml.default | 2 + 4 files changed, 316 insertions(+) create mode 100644 ScannerBit/include/gambit/ScannerBit/scanners/diver_1.3.0/diver.hpp create mode 100755 ScannerBit/src/scanners/diver_1.3.0/diver.cpp diff --git a/ScannerBit/include/gambit/ScannerBit/scanners/diver_1.3.0/diver.hpp b/ScannerBit/include/gambit/ScannerBit/scanners/diver_1.3.0/diver.hpp new file mode 100644 index 0000000000..ec7b1a83e4 --- /dev/null +++ b/ScannerBit/include/gambit/ScannerBit/scanners/diver_1.3.0/diver.hpp @@ -0,0 +1,47 @@ +// GAMBIT: Global and Modular BSM Inference Tool +// ********************************************* +/// \file +/// +/// ScannerBit interface to Diver 1.3.0 +/// +/// Header file +/// +/// ********************************************* +/// +/// Authors (add name and date if you modify): +/// +/// \author Pat Scott +/// (patrickcolinscott@gmail.com) +/// \date 2025 Apr +/// +/// ********************************************* + +#pragma once + +#include "gambit/ScannerBit/scanner_plugin.hpp" + +// C++ prototype of the main run_de function for Diver. +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_3_0 + { + + /// Structure for passing likelihood and printer data through Diver to the objective function. + struct diverScanData + { + Scanner::like_ptr likelihood_function; + Scanner::printer_interface* printer; + }; + + /// Function to be minimised by Diver + double objective(double params[], const int param_dim, int &fcall, bool &quit, const bool validvector, void*& context); + + } + +} diff --git a/ScannerBit/src/scanners/diver_1.3.0/diver.cpp b/ScannerBit/src/scanners/diver_1.3.0/diver.cpp new file mode 100755 index 0000000000..5b45a7bd49 --- /dev/null +++ b/ScannerBit/src/scanners/diver_1.3.0/diver.cpp @@ -0,0 +1,241 @@ +// GAMBIT: Global and Modular BSM Inference Tool +// ********************************************* +/// \file +/// +/// ScannerBit interface to Diver 1.3.0 +/// +/// ********************************************* +/// +/// Authors (add name and date if you modify): +/// +/// \author Pat Scott +/// (patrickcolinscott@gmail.com) +/// \date 2025 Apr +/// +/// ********************************************* + +#include +#include +#include + +#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" +#include "gambit/Utils/variadic_functions.hpp" + +/// ================================================= +/// Interface to ScannerBit +/// ================================================= + +scanner_plugin(diver, version(1, 3, 0)) +{ + + // Access Diver stuff and standard Gambit things + using namespace Gambit; + using namespace Gambit::Diver_1_3_0; + + // Error thrown if the following entries are not present in the inifile + reqd_inifile_entries("NP"); + + // Tell cmake to search for the diver library. + reqd_libraries("diver"); + + // Set up the scan data container + diverScanData data; + + // Code to execute when the plugin is loaded. + plugin_constructor + { + // Retrieve the external likelihood calculator + data.likelihood_function = get_purpose(get_inifile_value("like")); + if (data.likelihood_function->getRank() == 0) cout << "Loading Diver differential evolution plugin for ScannerBit." << std::endl; + // Retrieve the external printer + data.printer = &(get_printer()); + // Do not allow GAMBIT's own likelihood calculator to directly shut down the scan. + // Diver will assume responsibility for this process, triggered externally by + // the 'plugin_info.early_shutdown_in_progress()' function. + data.likelihood_function->disable_external_shutdown(); + } + + int plugin_main (void) + { + // Path to save Diver samples, resume files, etc + str defpath = get_inifile_value("default_output_path"); + str root = Utils::ensure_path_exists(get_inifile_value("path",defpath+"Diver/native")); + + // Ask the printer if this is a resumed run or not, and check that the necessary files exist if so. + bool resume = get_printer().resume_mode(); + if (resume) + { + bool good = true; + static const std::vector names = initVector(root+".rparam", root+".devo", root+".raw"); + for (auto it = names.begin(); it != names.end(); ++it) + { + std::ifstream file(*it); + good = good and file.good() and (file.peek() != std::ifstream::traits_type::eof()); + file.close(); + } + if (not good) + { + std::ostringstream warning; + warning << "Cannot resume previous Diver run because one or all of" << endl; + for (auto it = names.begin(); it != names.end(); ++it) warning << " " << *it << endl; + warning << "is missing or empty. This is probably because your last run didn't " << endl + << "complete even one generation. Diver will start from scratch, " << endl + << "as if you had specified -r."; + if (data.likelihood_function->getRank() == 0) cout << "WARNING: " << warning.str() << endl; + scan_warn << warning.str() << scan_end; + resume = false; + } + } + + // Retrieve the global option specifying the minimum interesting likelihood. + double gl0 = get_inifile_value("likelihood: model_invalid_for_lnlike_below"); + // Retrieve the global option specifying the likelihood offset to use + double offset = get_inifile_value("likelihood: lnlike_offset", 1e-4*gl0); + // Make sure the likleihood functor knows to apply the offset internally in ScannerBit + data.likelihood_function->setPurposeOffset(offset); + // Offset the minimum interesting likelihood by the offset, and flip it to match diver sign convention. + gl0 = -1.0 * (gl0 + offset); + + // Other Diver run parameters + 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 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 + double lambda = get_inifile_value("lambda", 0.0); // Mixing factor between best and rand/current + bool current = get_inifile_value ("current", false); // Use current vector for mutation + bool expon = get_inifile_value ("expon", false); // Use exponential crossover + int bndry = get_inifile_value ("bndry", 3); // Boundary constraint: 1=brick wall, 2=random re-initialization, 3=reflection + bool jDE = get_inifile_value ("jDE", true); // Use self-adaptive choices for rand/1/bin parameters as per Brest et al 2006 + bool lambdajDE = get_inifile_value ("lambdajDE", true); // Use self-adaptive rand-to-best/1/bin parameters; based on Brest et al 2006 + 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 + int savecount = get_inifile_value ("savecount", 1); // Save progress every savecount generations + 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+=population info + int seed = get_inifile_value ("seed", -1); // Base seed for random number generation; non-positive means seed from the system clock + void* context = &data; // Pointer to GAMBIT likelihood function and printers, passed through to objective function. + + // Copy the contents of root to a char array. + std::vector path(root.length()+1); + strcpy(&path[0], root.c_str()); + + // Unit cube boundaries + 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)); + 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>>(); + + // 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; + + // 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, &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; + + } + +} + +/// ================================================= +/// Function definitions +/// ================================================= + +namespace Gambit +{ + + namespace Diver_1_3_0 + { + + //Function to be minimized. Corresponds to -ln(Likelihood). Redirects to the target of context pointer. + double objective(double params[], const int param_dim, int &fcall, bool &quit, const bool validvector, void*& context) + { + // Return the worst possible likelihood if the point is outside the prior box. + if (not validvector) return std::numeric_limits::max(); + + // Put the parameters into a C++ vector + std::vector param_vec(params, params + param_dim); + + // Retrieve the likelihood function from the context pointer and call it + diverScanData* data = static_cast(context); + double lnlike = data->likelihood_function(param_vec); + + // Increment the number of function calls, tell Diver to continue and return the likelihood + fcall += 1; + + // Check whether the calling code wants us to shut down early + quit = Gambit::Scanner::Plugins::plugin_info.early_shutdown_in_progress(); + + return -lnlike; + + } + + } + +} + diff --git a/cmake/scanners.cmake b/cmake/scanners.cmake index c093dae453..b4022e5361 100644 --- a/cmake/scanners.cmake +++ b/cmake/scanners.cmake @@ -130,6 +130,32 @@ 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() + +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: From ab88134511c3f3fcdeefbbcb32d02d4ff6cc8c08 Mon Sep 17 00:00:00 2001 From: Pat Scott Date: Sun, 6 Apr 2025 00:13:12 +1000 Subject: [PATCH 2/7] Add check that initial guess parameter names match those of the scan modified: ScannerBit/src/scanners/diver_1.3.0/diver.cpp --- ScannerBit/src/scanners/diver_1.3.0/diver.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ScannerBit/src/scanners/diver_1.3.0/diver.cpp b/ScannerBit/src/scanners/diver_1.3.0/diver.cpp index 5b45a7bd49..8e2281d5c0 100755 --- a/ScannerBit/src/scanners/diver_1.3.0/diver.cpp +++ b/ScannerBit/src/scanners/diver_1.3.0/diver.cpp @@ -161,6 +161,16 @@ scanner_plugin(diver, version(1, 3, 0)) 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 those being scanned. + const std::vector valid_parameters = data.likelihood_function->getPrior().getShownParameters(); + 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 those being scanned over." << 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); From 1dcd77819c5812ee2a808023941cce538894e620 Mon Sep 17 00:00:00 2001 From: Pat Scott Date: Sun, 6 Apr 2025 00:59:50 +1000 Subject: [PATCH 3/7] Improve check of initial guess parameter names modified: ScannerBit/src/scanners/diver_1.3.0/diver.cpp --- ScannerBit/src/scanners/diver_1.3.0/diver.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ScannerBit/src/scanners/diver_1.3.0/diver.cpp b/ScannerBit/src/scanners/diver_1.3.0/diver.cpp index 8e2281d5c0..aea5efa5df 100755 --- a/ScannerBit/src/scanners/diver_1.3.0/diver.cpp +++ b/ScannerBit/src/scanners/diver_1.3.0/diver.cpp @@ -161,13 +161,16 @@ scanner_plugin(diver, version(1, 3, 0)) 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 those being scanned. - const std::vector valid_parameters = data.likelihood_function->getPrior().getShownParameters(); + // Make sure the parameter names all match up to ones being scanned. + const std::unordered_map valid_parameter_map = data.likelihood_function->transform(std::vector(nPar, 0.5)); for (auto parname : ig_parnames) { - if (not std::count(valid_parameters.begin(), valid_parameters.end(), parname)) + if (valid_parameter_map.find(parname) == valid_parameter_map.end()) { - scan_err << "Parameter " << parname << " specified in \"initial_guesses\" is not one of those being scanned over." << scan_end; + std::vector valid_parameters; + for (const std::pair p : valid_parameter_map) valid_parameters.push_back(p.first); + scan_err << "Parameter " << parname << " specified in \"initial_guesses\" is not one of the following being scanned over:" + << endl << " " << valid_parameters << scan_end; } } From f50c00217fd51a9194c7f88178058bc6e9f50f2f Mon Sep 17 00:00:00 2001 From: Pat Scott Date: Sun, 6 Apr 2025 01:03:46 +1000 Subject: [PATCH 4/7] Remove diver 1.0.5 and add initial_guesses to example yaml --- ScannerBit/src/scanners/diver_1.0.5/diver.cpp | 200 ------------------ cmake/scanners.cmake | 2 + yaml_files/gambit_light_example.yaml | 9 +- 3 files changed, 10 insertions(+), 201 deletions(-) delete mode 100755 ScannerBit/src/scanners/diver_1.0.5/diver.cpp diff --git a/ScannerBit/src/scanners/diver_1.0.5/diver.cpp b/ScannerBit/src/scanners/diver_1.0.5/diver.cpp deleted file mode 100755 index 73886d1477..0000000000 --- a/ScannerBit/src/scanners/diver_1.0.5/diver.cpp +++ /dev/null @@ -1,200 +0,0 @@ -// GAMBIT: Global and Modular BSM Inference Tool -// ********************************************* -/// \file -/// -/// ScannerBit interface to Diver 1.0.5 -/// -/// ********************************************* -/// -/// Authors (add name and date if you modify): -/// -/// \author Pat Scott -/// (p.scott@imperial.ac.uk) -/// \date 2017 June, Nov -/// -/// ********************************************* - -#include -#include -#include - -#include "gambit/ScannerBit/scanners/diver_1.0.5/diver.hpp" -#include "gambit/Utils/yaml_options.hpp" -#include "gambit/Utils/util_types.hpp" -#include "gambit/Utils/util_functions.hpp" -#include "gambit/Utils/variadic_functions.hpp" - -/// ================================================= -/// Interface to ScannerBit -/// ================================================= - -scanner_plugin(diver, version(1, 0, 5)) -{ - - // Access Diver stuff and standard Gambit things - using namespace Gambit; - using namespace Gambit::Diver_1_0_5; - - // Error thrown if the following entries are not present in the inifile - reqd_inifile_entries("NP"); - - // Tell cmake to search for the diver library. - reqd_libraries("diver"); - - // Set up the scan data container - diverScanData data; - - // Code to execute when the plugin is loaded. - plugin_constructor - { - // Retrieve the external likelihood calculator - data.likelihood_function = get_purpose(get_inifile_value("like")); - if (data.likelihood_function->getRank() == 0) cout << "Loading Diver differential evolution plugin for ScannerBit." << std::endl; - // Retrieve the external printer - data.printer = &(get_printer()); - // Do not allow GAMBIT's own likelihood calculator to directly shut down the scan. - // Diver will assume responsibility for this process, triggered externally by - // the 'plugin_info.early_shutdown_in_progress()' function. - data.likelihood_function->disable_external_shutdown(); - } - - int plugin_main (void) - { - // Path to save Diver samples, resume files, etc - str defpath = get_inifile_value("default_output_path"); - str root = Utils::ensure_path_exists(get_inifile_value("path",defpath+"Diver/native")); - - // Ask the printer if this is a resumed run or not, and check that the necessary files exist if so. - bool resume = get_printer().resume_mode(); - if (resume) - { - bool good = true; - static const std::vector names = initVector(root+".rparam", root+".devo", root+".raw"); - for (auto it = names.begin(); it != names.end(); ++it) - { - std::ifstream file(*it); - good = good and file.good() and (file.peek() != std::ifstream::traits_type::eof()); - file.close(); - } - if (not good) - { - std::ostringstream warning; - warning << "Cannot resume previous Diver run because one or all of" << endl; - for (auto it = names.begin(); it != names.end(); ++it) warning << " " << *it << endl; - warning << "is missing or empty. This is probably because your last run didn't " << endl - << "complete even one generation. Diver will start from scratch, " << endl - << "as if you had specified -r."; - if (data.likelihood_function->getRank() == 0) cout << "WARNING: " << warning.str() << endl; - scan_warn << warning.str() << scan_end; - resume = false; - } - } - - // Retrieve the global option specifying the minimum interesting likelihood. - double gl0 = get_inifile_value("likelihood: model_invalid_for_lnlike_below"); - // Retrieve the global option specifying the likelihood offset to use - double offset = get_inifile_value("likelihood: lnlike_offset", 1e-4*gl0); - // Make sure the likleihood functor knows to apply the offset internally in ScannerBit - data.likelihood_function->setPurposeOffset(offset); - // Offset the minimum interesting likelihood by the offset, and flip it to match diver sign convention. - 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 - 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 - double lambda = get_inifile_value("lambda", 0.0); // Mixing factor between best and rand/current - bool current = get_inifile_value ("current", false); // Use current vector for mutation - bool expon = get_inifile_value ("expon", false); // Use exponential crossover - int bndry = get_inifile_value ("bndry", 3); // Boundary constraint: 1=brick wall, 2=random re-initialization, 3=reflection - bool jDE = get_inifile_value ("jDE", true); // Use self-adaptive choices for rand/1/bin parameters as per Brest et al 2006 - bool lambdajDE = get_inifile_value ("lambdajDE", true); // Use self-adaptive rand-to-best/1/bin parameters; based on Brest et al 2006 - 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) - 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 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. - std::vector path(root.length()+1); - strcpy(&path[0], root.c_str()); - - // Unit cube boundaries - 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 - - // Scale factors - std::vector Fvec = get_inifile_value >("F", initVector(0.7)); - int nF = Fvec.size(); // Size of the array indicating scale factors - - // 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. - - // 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, - 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; - - } - -} - -/// ================================================= -/// Function definitions -/// ================================================= - -namespace Gambit -{ - - namespace Diver_1_0_5 - { - - //Function to be minimized. Corresponds to -ln(Likelihood). Redirects to the target of context pointer. - double objective(double params[], const int param_dim, int &fcall, bool &quit, const bool validvector, void*& context) - { - // Return the worst possible likelihood if the point is outside the prior box. - if (not validvector) return std::numeric_limits::max(); - - // Put the parameters into a C++ vector - std::vector param_vec(params, params + param_dim); - - // Retrieve the likelihood function from the context pointer and call it - diverScanData* data = static_cast(context); - double lnlike = data->likelihood_function(param_vec); - - // Increment the number of function calls, tell Diver to continue and return the likelihood - fcall += 1; - - // Check whether the calling code wants us to shut down early - quit = Gambit::Scanner::Plugins::plugin_info.early_shutdown_in_progress(); - - return -lnlike; - - } - - } - -} - diff --git a/cmake/scanners.cmake b/cmake/scanners.cmake index b4022e5361..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") @@ -142,6 +143,7 @@ if(NOT ditched_${name}_${ver}) ) add_extra_targets("scanner" ${name} ${ver} ${dir} ${dl} clean) endif() +endif() # End if(NOT GAMBIT_LIGHT) set(name "diver") set(ver "1.3.0") diff --git a/yaml_files/gambit_light_example.yaml b/yaml_files/gambit_light_example.yaml index 13b0542214..1f84f3b60f 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: @@ -182,6 +182,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::p8] # 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 From 378dbbc8aa3e26337a497d57fe923e4ed96fd471 Mon Sep 17 00:00:00 2001 From: Pat Scott Date: Sun, 6 Apr 2025 01:13:09 +1000 Subject: [PATCH 5/7] Remove debug change modified: yaml_files/gambit_light_example.yaml --- yaml_files/gambit_light_example.yaml | 54 ++++++++++++++-------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/yaml_files/gambit_light_example.yaml b/yaml_files/gambit_light_example.yaml index 1f84f3b60f..deecc19826 100644 --- a/yaml_files/gambit_light_example.yaml +++ b/yaml_files/gambit_light_example.yaml @@ -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: @@ -97,7 +97,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: @@ -134,22 +134,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: @@ -183,7 +183,7 @@ Scanner: 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::p8] # Explains which parameter is which in the starting guesses. Be sure to use originals rather than parameters declared "same_as". + 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 @@ -202,7 +202,7 @@ Scanner: outfile: true # Write output files? seed: -1 # Seed for random number generator. Negative means seed from system time. - # Note: + # Note: # The multinest scanner cannot be used together with the hdf5_v1 printer. multinest: plugin: multinest @@ -271,7 +271,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 @@ -291,7 +291,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 @@ -313,7 +313,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 @@ -327,7 +327,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 @@ -345,7 +345,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: @@ -375,7 +375,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 @@ -400,7 +400,7 @@ Scanner: run: dlogz: 0.5 checkpoint_every: 60 - + dynamic_dynesty: like: LogLike plugin: dynamic_dynesty @@ -483,7 +483,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 From 53b46c9937020db5bed0760f39dc7288d90da98c Mon Sep 17 00:00:00 2001 From: Pat Scott Date: Sun, 6 Apr 2025 01:15:13 +1000 Subject: [PATCH 6/7] Indentation modified: yaml_files/gambit_light_example.yaml --- yaml_files/gambit_light_example.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yaml_files/gambit_light_example.yaml b/yaml_files/gambit_light_example.yaml index deecc19826..848de0d72d 100644 --- a/yaml_files/gambit_light_example.yaml +++ b/yaml_files/gambit_light_example.yaml @@ -185,9 +185,9 @@ Scanner: 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 + - [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: From c114cdffb548c85b668575073d0e974f5651d372 Mon Sep 17 00:00:00 2001 From: Pat Scott Date: Sun, 6 Apr 2025 13:20:09 +1000 Subject: [PATCH 7/7] Add new getSetParameters function to priors, for checking precisely which parameters they set, and therefore which parameters need to be specified in order to use theire inverse_transform method. Also updated Diver 1.3 interface to use getSetParameters as a more robust way of checking that the parameters provided by the user as initial guesses are the same as those being scanned. modified: ScannerBit/include/gambit/ScannerBit/base_prior.hpp modified: ScannerBit/include/gambit/ScannerBit/priors/composite.hpp modified: ScannerBit/src/priors/composite.cpp modified: ScannerBit/src/scanners/diver_1.3.0/diver.cpp --- .../include/gambit/ScannerBit/base_prior.hpp | 14 +- .../gambit/ScannerBit/priors/composite.hpp | 39 ++-- ScannerBit/src/priors/composite.cpp | 168 +++++++++--------- ScannerBit/src/scanners/diver_1.3.0/diver.cpp | 6 +- 4 files changed, 115 insertions(+), 112 deletions(-) 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/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.3.0/diver.cpp b/ScannerBit/src/scanners/diver_1.3.0/diver.cpp index aea5efa5df..1547f22a8b 100755 --- a/ScannerBit/src/scanners/diver_1.3.0/diver.cpp +++ b/ScannerBit/src/scanners/diver_1.3.0/diver.cpp @@ -162,13 +162,11 @@ scanner_plugin(diver, version(1, 3, 0)) std::vector> ig_values = initial_guesses_node["values"].as>>(); // Make sure the parameter names all match up to ones being scanned. - const std::unordered_map valid_parameter_map = data.likelihood_function->transform(std::vector(nPar, 0.5)); + const std::vector valid_parameters = data.likelihood_function->getPrior().getSetParameters(); for (auto parname : ig_parnames) { - if (valid_parameter_map.find(parname) == valid_parameter_map.end()) + if (not std::count(valid_parameters.begin(), valid_parameters.end(), parname)) { - std::vector valid_parameters; - for (const std::pair p : valid_parameter_map) valid_parameters.push_back(p.first); scan_err << "Parameter " << parname << " specified in \"initial_guesses\" is not one of the following being scanned over:" << endl << " " << valid_parameters << scan_end; }