rmcantin / bayesopt

BayesOpt: A toolbox for bayesian optimization, experimental design and stochastic bandits.
GNU Affero General Public License v3.0
396 stars 92 forks source link

Utilise Boost to provide some sort of clue for unknown errors #31

Open NeutralKaon opened 10 months ago

NeutralKaon commented 10 months ago

Hi there,

a) Thanks for providing bayesopt -- I am having fun with it and my multidimensional optimisation problems!

b) Please forgive this somewhat specific / longwinded way of asking for a diff to be merged, provided below, for what is undoubtedly technically a Matlab bug. I am providing a vast amount of information in case it helps someone else. On the Matlab (R2023a) interface, I was trying to optimise a 37-dimensional function that returns essentially the least squares difference of a simulation and experimental data. I had defined two functions: (i) optimFun(x) as an anonymous function, and AFullSimulation(x, parameters_1, parameters2, options,experimental_data) differently; that is AFullSimulation(...) was defined separately and optimFun = @(x) (AFullSimulation(x, Sys1, Exp, Options,...) was defined inline in the matlab file I was trying to run. Trying to call bayesoptcont(@optimFun,...) directly failed -- with "Error: -1" returned and ERROR: Unknown error in the log. I tried to understand this and tried iterations such as bayesoptcont('optimFun') etc but to no avail.

I therefore edited the wrapper function's generic, all-purpose catch(...) statement to provide a specific error class if one was available, utilising a feature in boostlib, which you are already linking against:

diff --git a/src/wrappers/bayesoptwpr.cpp b/src/wrappers/bayesoptwpr.cpp
index 2d38591..eeb13d3 100644
--- a/src/wrappers/bayesoptwpr.cpp
+++ b/src/wrappers/bayesoptwpr.cpp
@@ -26,6 +26,7 @@
 #include "log.hpp"
 #include "ublas_extra.hpp"
 #include "specialtypes.hpp"
+#include <boost/exception/diagnostic_information.hpp>

 static const int BAYESOPT_FAILURE = -1; /* generic failure code */
 static const int BAYESOPT_INVALID_ARGS = -2;
@@ -134,7 +135,8 @@ int bayes_optimization(int nDim, eval_func f, void* f_data,
     }
   catch (...)
     {
-      FILE_LOG(logERROR) << "Unknown error";
+      FILE_LOG(logERROR) << "Unknown error building continuous optimizer!" << std::endl;
+      FILE_LOG(logERROR) << boost::current_exception_diagnostic_information() << std::endl; /* Provide debug information if available */
       return BAYESOPT_FAILURE;
     }
   return 0; /* everything ok*/
@@ -192,7 +194,8 @@ int bayes_optimization_disc(int nDim, eval_func f, void* f_data,
     }
   catch (...)
     {
-      FILE_LOG(logERROR) << "Unknown error";
+      FILE_LOG(logERROR) << "Unknown error building discrete optimizer!" << std::endl;
+      FILE_LOG(logERROR) << boost::current_exception_diagnostic_information() << std::endl; /* Provide debugging info if it is there */
       return BAYESOPT_FAILURE;
     }

For my specific Matlab woe, this helpfully prints out the following:

[...] ERROR: Dynamic exception type: foundation::core::except::Exception<MATLAB::legacy_two_part::undefinedFunctionTextInputArgumentsType, std::exception, void> std::exception::what: Undefined function 'optimFun' for input arguments of type 'double'

Replacing @optimFun or 'optimFun' with @(x) AFullSimulation(x,...) (i.e. its full definition writ-large) appears to make Matlab JIT it into something that the mex interface is happy with.

I'm happy to submit this as a pull request if you like but thought I'd reach out first (!).

rmcantin commented 10 months ago

Thanks for the contribution. I haven't been using Matlab for a while and I'm pretty sure that the wrapper can be improved a lot.

I'll check that boost component. Maybe we can use it in other wrappers, too.