2026-01-26 Release 3 Summary: * Change build system from handwritten Makefiles to CMake. * Add support for NLopt SLSQP as the NLP solver. Make it the default in CMake. * Add support for DONLP3 (reentrant C++ version of DONLP2) as the NLP solver. * Add support for dynamic allocation so that problems can be loaded at runtime. * Eliminate global/static variables to make BBOWDA fully reentrant. * Add a reentrant, callback-driven procedural function interface to BBOWDA. * Build a libbbowda library making that interface available as an API. * Add a reentrant object-oriented C++ binding to BBOWDA (bbowdapp). * Build a libbbowdapp library making that interface available as an API. * Add Doxygen documentation for the public C and C++ API. * Add Java and Python 3 bindings to BBOWDA (actually to bbowdapp) using SWIG. * Add Sphinx documentation for the Python binding API. * Add Javadoc documentation for the Java binding API. * Automatically find system copies of lp_solve, Ipopt, NLopt, SWIG, Python 3, Sphinx, Java. * Update license exception for new dependency licenses. Full list of changes: * Makefile, Makefile.ipopt: Delete. Replaced by CMakeLists.txt. * CMakeLists.txt: New build system. Allows selecting the NLP solver with a flag instead of having 2 or 3 separate makefiles. Also finds libraries more portably. System copies of lp_solve, Ipopt (instead of a relative path to a build directory), and NLopt (new NLP solver option) are now located automatically. The default NLP solver is now NLopt SLSQP because it is the most efficient FOSS NLP solver for the low-dimensional NLPs (surrogate and density models) used in BBOWDA. DONLP2 has licensing issues (and CMakeLists.txt now warns about that), and Ipopt has performance issues, NLopt has neither. * README.txt: Make much more verbose and document the CMake options. * bbowda.kdev4: New KDevelop project. * covar.c, covar.h: Replace static arrays with pointers, using macros casting them to pointers to C99 dynamically-sized arrays to handle the variable-size multi-dimensional arrays. Add alloc_covar method. * eqconst.c, eqconst.h: Replace static arrays likewise. Make GLOBAL_SEARCH_IGNORES_EQ_CONSTRAINTS a variable instead of a #defined constant (i.e., check it with if instead of #ifdef). * eval.c, eval.h, gmmem.c, gmmem.h, ipopt.c, userfu.c, nlopt.h: Replace static arrays likewise. * probldim.h: Delete. The constants previously #defined here are now runtime variables declared extern in problem.h and defined in problem.c. * problem.h: Declare extern variables for the former probldim.h constants. Replace static arrays likewise to covar.c etc. Declare init_problem method. * problem.c: Implement the former probldim.h constants as C constants and retain the empty init_problem and the evaluate_F C function. That code is designed to be edited directly to implement a problem in C. * main.c: Call init_problem() before init_points(). Adapt to the dimensions being variable. Call alloc_covar() before the optimization loop. * download_donlp2.sh: New download script for donlp2_intv_dyn. * nlp_nlopt.c, nlp_nlopt.h: New files. NLopt SLSQP backend. * Rename userfu.c to nlp_donlp2.c, donlp2.h to nlp_donlp2.h, ipopt.c to nlp_ipopt.c, and ipopt.h to nlp_ipopt.h. * nlpopt.h: Include nlp_nlopt.h instead of nlp_donlp2.h/nlp_ipopt.h if USE_NLOPT is defined (by CMakeLists.txt with the default -DNLP_SOLVER=NLopt). * license.txt: Update for the new MUMPS license (CeCILL-C v1). Clarify the "or (at your option) any later version" clauses with an example explicitly mentioning that the EPL 2.0 used by the latest Ipopt is allowed. Update the license headers in all source files to match the license.txt changes. * Move download_donlp2.sh, nlp_donlp2.c, nlp_donlp2.h, patches/donlp2-fmin.diff, and patches/donlp2-use-float.h.diff to a new nlp_donlp2/ directory, and the DONLP2 files extracted from donlp2_intv_dyn.tar.gz to a new nlp_donlp2/donlp2_intv_dyn/ sub directory. * .gitignore: Update accordingly (ignore /nlp_donlp2/donlp2_intv_dyn/ instead of individual DONLP2 files under /.) * Move nlp_ipopt.c, nlp_ipopt.h, patches/ipopt-fix-makefiles.diff, and patches/Makefile.inc to a new nlp_ipopt/ directory. * Move nlp_nlopt.c, nlp_nlopt.h, and patches/nlopt-2.8.0-fix-slsqp.patch to a new nlp_nlopt/ directory. * nlp_donlp2.h. nlp_ipopt.h, nlp_nlopt.h: Move declaration of solve_nlp to the common nlpopt.h. Convert the macro in nlp_donlp2.h to a real function in nlp_donlp2.c, also allowing to avoid exposing donlp2() and optite. * nlp_*/nlp_*.c, nlpopt.h: Make the global variables optimum_x, optimization_problem, and ignore_constraints parameters of the solve_nlp function instead. * nlp_donlp2/nlp_donlp2.c (solve_nlp): Save them to static variables so that the callbacks called by donlp2 (including user_init_size and user_init) can use them. * nlp_ipopt/nlp_ipopt.c (eval_g_1, eval_jac_g_1, eval_h_1): Use the passed m instead of ignore_constraints and num_estimate_constraints. * main.c: Adapt the calls accordingly. * covar.c, covar.h, eqconst.c, eqconst.h, eval.c, eval.h, gmmem.c, gmmem.h, main.c, nlp_*/nlp_*.c, nlpopt.h: Move all the global and static variables (remaining after the above) to structs. Add the required structs as function arguments to the functions requiring them, and add new free_covar (covar.c), alloc_eqc_estimates, and free_eqc_estimates (eqconst.c) methods. Change the macros that typecast simple pointers to pointers to multi-dimensional variable-size arrays to take the struct pointer as an argument; C syntax unfortunately does not allow a macro to hide the typecast completely transparently for struct members, as was possible for the global variables. Adapt the calls and variable references accordingly to all these changes. * gmmem.c (free_gmm): Also free the struct GMM itself (as for the newly added free_* methods). * problem.h, problem.c (DIMX, DIMY, DIMY_EQ, NUMINITPTS, c, xlow, xup, Flow, Fup, initpts_p): Move these global variables to a new struct bbowda_problem. Lowercase the names (except Flow, Fup). (DIMX, DIMY, DIMY_EQ): Since these dimensions are used so frequently, add macros for them expanding to (problem->dimx) etc. (MAXPTS, DOUBLE OPTIMUM_TOL, GLOBAL_SEARCH_IGNORES_EQ_CONSTRAINTS, ESTIMATE_CONSTRAINT_TOL): Move these global variables to a new struct bbowda_params. Lowercase the names. (init_problem): Return a void *user_data for evaluate_F. (evaluate_F): Take new const struct bbowda_problem *problem and void *user_data arguments. * problem.c, covar.c, covar.h, eqconst.c, eqconst.h, eval.c, eval.h, gmmem.c, gmmem.h, main.c, nlp_*/nlp_*.c, nlpopt.h: Pass const struct bbowda_problem *problem wherever needed (many places), and individual parameters from bbowda_params wherever those are needed. * covar.c (build_local_regcovar_model, compare_yeq): Adapt to use qsort_r (POSIX) or qsort_s (W32/W64), needed to pass the problem pointer to the callback. * eqconst.c, eqconst.h (compute_global_eq_cst_estimates_around): Always actually add the equality constraint estimates, let the caller handle the global_search_ignores_eq_constraints parameter. Return void instead of struct estimate_constraints * (see eqc_get_estimatec below). (eqc_get_estimatec): New function. Takes a struct eqc_estimates * and returns the corresponding struct estimate_constraints *. * main.c (main): Only call compute_1st_global_eq_cst_estimates if !params->global_search_ignores_eq_constraints. Call eqc_get_estimatec explicitly and unconditionally. Pass NULL instead of eqc to new_point if params->global_search_ignores_eq_constraints so that it will not call compute_global_eq_cst_estimates_around. * nlpopt.h, nlp_*/nlp_*.c (solve_nlp): Rename the void *problem_data argument to void *data to prevent a name conflict. * nlp_nlopt/nlp_ipopt.c (solve_nlp): Rename the local variable problem to ipopt_problem to prevent a name conflict. * nlp_nlopt/nlp_nlopt.c (solve_nlp): Use alloca instead of compound literals to allocate temporary user data structures. They need to live until the end of solve_nlp, not just the end of the nested scope. Rename the local variable problem to opt to prevent a name conflict. * nlp_donlp3/donlp3_c_binding/{CMakeLists.txt,donlp3_c_binding.{cc,h}}: New files. C binding for DONLP3, the reentrant C++ version of DONLP2. * nlp_donlp3/nlp_donlp3.c, nlp_donlp3/nlp_donlp3.h: New files. DONLP3 backend. * CMakeLists.txt: Add support for it. * nlpopt.h: Include nlp_donlp3.h instead of nlp_donlp2.h if USE_DONLP3 is defined (by CMakeLists.txt with -DNLP_SOLVER=donlp3). * eval.c, eval.h (init_points, new_point, extrapolate_point): Add evaluate_F function pointer argument. * main.c (main): Factor out a bbowda function. Include "bbowda.h". (enable_global_search, bbowda): Move to... * bbowda.c: ... this new file. (bbowda): Take an additional evaluate_F function pointer argument and pass it to the eval.c functions. * bbowda.h: New header file, declaring the bbowda function. * CMakeLists.txt: Add bbowda.c to SOURCES. * problem.h (struct bbowda_problem, struct bbowda_params): Move these structures to bbowda.h. They are part of the BBOWDA API and as such should be declared in bbowda.h. * problem.c: Delete. Move its contents to... * main.c: ...here. Do not include "problem.h". Make all functions except main static. (init_problem, evaluate_F): Do not use the DIMX, DIMY, and DIMY_EQ convenience macros defined in problem.h. These are considered internal to BBOWDA, the public API must not pollute the namespace that way. Just explicitly use problem->dimx, problem->dimy, resp. problem->dimy_eq instead. * CMakeLists.txt: Remove problem.c from SOURCES. Replace reference to problem.c in a message with main.c. * README.txt: Replace all references to problem.c with main.c. * CMakeLists.txt: Build a libbbowda library and link the example exe to it. * README.txt: Mention it in the "HOW_TO_USE" section. * bbowda.h: Make C++-safe (add extern "C" {} #ifdef __cplusplus). * main.c: Remove unused #include . * bbowdapp/bbowdapp.hh, bbowdapp/bbowdapp.cc: New files. Object-oriented C++ binding for bbowda. * bbowdapp/main.cc: New file, port of main.c to C++/bbowdapp. * bbowdapp/CMakeLists.txt: New file. Builds libbbowdapp and bbowdapp_example. * CMakeLists.txt: Add WITH_CXX option, defaulting to ON. Add BBOWDA_SHARED option replacing BUILD_SHARED_LIBS, so that it can be defined separately from BBOWDAPP_SHARED. (E.g., if you have only C++ client programs, you may want to define BBOWDA_SHARED=OFF and BBOWDAPP_SHARED=ON to get a single libbbowdapp.so statically linked to libbbowda.a.) Install libbbowda. Rename exe to bbowda_example and install it to ${CMAKE_INSTALL_BINDIR} instead of hardcoded bin. Add bbowdapp subdirectory if(WITH_CXX). * README.txt: Update CMake options and rewrite "HOW TO USE" section. * DOUBLE (taken from the NLP solver) replaced with plain double throughout the code, because it is always double in practice anyway (but CMakeLists.txt now makes CMake check it to be sure) and because implementation details of the underlying NLP solver should not be leaked in the API. This allows removing unnecessary #include "nlpopt.h" in many places. * nlp_*/nlp_*.h: Do not #include NLP solver headers, #include them directly in nlp_*/nlp_*.c instead. They were needed only to provide DOUBLE, TRUE, FALSE. * nlp_nlopt/nlp_nlopt.h: Remove #define DOUBLE Number, #define TRUE 1, and #define FALSE 0. * bbowda.c: #include and replace TRUE with true, FALSE with false everywhere. * eqconst.c: Remove no longer needed #undef TRUE and #undef FALSE. * CMakeLists.txt: Add WITH_DOXYGEN option, defaulting to ON. If enabled, find Doxygen and use doxygen_add_docs to build the Doxygen documentation. * bbowda.h: Add a Doxygen @mainpage. Add Doxygen comments to everything in the public API. * bbowdapp/bbowdapp.hh: Add Doxygen comments to everything in the public API. Add a normal comment to the private helper, not part of the API. * CMakeLists.txt: If WITH_DOXYGEN, find PDFLaTeX and make, set DOXYGEN_GENERATE_LATEX to YES, and invoke make in the latex directory as a POST_BUILD command for the doc target. * bbowdapp/CMakeLists.txt: Add WITH_PYTHON and WITH_JAVA options, building the SWIG Python 3 resp. Java bindings for bbowdapp, defaulting to ON. Add a WITH_SWIG variable defined as (WITH_PYTHON OR WITH_JAVA), and if(WITH_SWIG), add_subdirectory(swig). * README.txt: Document the new WITH_JAVA and WITH_PYTHON CMake flags. * CMakeLists.txt: Reorder option statements for consistency. * bbowdapp/bbowdapp.hh (OptimizationProblem::OptimizationProblem (both overloads)): Add optional argument copyVectors=true (whether to copy the vectors). Only enable the delegating template overload #if __cplusplus >= 201103L, because delegating constructors are not available below C++11 (and copy&paste as an alternative is not desirable because we want the necessarily inline template to call the out-of-line normal constructor due to binary compatibility concerns). (OptimizationProblem::~OptimizationProblem): Add virtual destructor. (m_freeVectors): New private member variable of type bool. * bbowdapp/bbowdapp.cc (dvecdup): New static helper function. Duplicates a double[] array with specified dimension. (OptimizationProblem::OptimizationProblem): Add the copyVectors argument to match the prototype in bbowdapp.h. if (copyVectors), call dvecdup on all the passed double[] arguments (with their expected dimensions) before setting the inherited bbowda_problem members to them. Initialize m_freeVectors to copyVectors. (OptimizationProblem::~OptimizationProblem): if (m_freeVectors), delete[] all the double[] members inherited from bbowda_problem. * bbowdapp/main.cc (initpts_data): Use a 1D array of dimension [NUM_INIT_PTS * DIM_X] instead of a 2D array of dimensions [NUM_INIT_PTS][DIM_X]. That way, the example does not require C++11, and it does not really matter because the array is empty anyway. (Problem::Problem): Pass copyVectors=false to the superclass Bbowda::OptimizationProblem constructor, in order to opt out of the copying that is not needed here. * bbowdapp/swig/CMakeLists.txt: New file. Builds the SWIG bindings and optionally (WITH_PYTHON_SPHINX and WITH_JAVA_JAVADOC options) the API documentation for them. * bbowdapp/swig/glob_java.cmake: New file. Helper CMake script that is invoked at build (make) time, not at configure (cmake) time. It is invoked by an add_custom_command in the main bbowdapp/swig/CMakeLists.txt that calls cmake -P on it. Globs the *.java files produced by SWIG and writes the result to java_sources.txt. * bbowdapp/swig/bbowda.i: New file. The SWIG interface file for the Java and Python bindings. Contains both common parts and parts under #ifdef SWIGJAVA resp. #ifdef SWIGPYTHON. Also contains Doxygen comments (for the SWIG Doxygen translation) and some manual Python docstrings and javadocs. * bbowdapp/swig/bbowda-python.dist-info.in: New file. Template for bbowda-${BBOWDA_RELEASE}.dist-info. * bbowdapp/swig/example.java: New file. Java port of the BBOWDA Rosenbrock example. * bbowdapp/swig/example.java.mf: New file. MANIFEST.MF template for the example JAR (bbowda_java_example.jar). Specifies Class-Path: bbowda.jar. * bbowdapp/swig/example.py: New file. Python port of the BBOWDA Rosenbrock example. * main.c: Rename to example.c. * bbowdapp/main.cc: Rename to example.cc. * CMakeLists.txt, bbowdapp/CMakeLists.txt, README.txt: Update accordingly. * buildscripts: New directory. Build scripts for portable JNI binaries. * bbowdapp/swig/cmake/FindSphinx.cmake: Import from https://github.com/k0ekk0ek/cmake-sphinx. Merge LICENSE into this file. Add introductory comment. Fix the import line in the check for Sphinx extensions so that the check actually passes. * bbowdapp/swig/sphinx/conf.py: New file. Configuration file for Sphinx. * bbowdapp/swig/sphinx/index.rst: New file. Root document for Sphinx. * CMakeLists.txt: Add option WITH_DOXYGEN_PDF, default OFF, and build the Doxygen LaTeX PDF only if it is ON. * bbowdapp/swig/CMakeLists.txt: Add options WITH_JAVA_JAVADOC_PDF and WITH_PYTHON_SPHINX_PDF, default OFF, and build the Java Javadoc PDF resp. the Python Sphinx LaTeX PDF if the respective option is ON. * README.txt: Document the new options. 2011-05-14 Release 2 * eval.c: fix missing #endif resulting from the code cleanup for the release * patches/donlp2-fmin.diff: new patch, fixes donlp2 compilation * Makefile, Makefile.ipopt: use the system lp_solve library * eqconst.c: use #include (system) instead of #include "lp_lib.h" * patches/lpsolve-5.5-enable-debug.diff: drop, should be handled by the system * patches/Makefile.inc: update for MUMPS 4.10.0 * patches/MUMPS-4.7.3-fix-uninitialized.diff: drop, fixed in newer MUMPS * Makefile.ipopt: update to use Ipopt 3.9.3 * patches/ipopt-fix-makefiles.diff: update for Ipopt 3.9.3 * patches/ipopt-3.3.1-fix-with-mumps-dir.diff: drop, fixed in newer Ipopt Note: Use --with-mumps-lib="-LMUMPS_4.10.0/lib -ldmumps -lmumps_common -lpord -LMUMPS_4.10.0/libseq -lmpiseq" --with-mumps-incdir="MUMPS_4.10.0/include -IMUMPS_4.10.0/libseq" instead of --with-mumps-dir with current versions of Ipopt. Another note: Use COIN_SKIP_PROJECTS=HSL to avoid building HSL stuff. * licenses.txt: update reproduced copy of the MUMPS Conditions of Use * licenses.txt, *.c, *.h: clarify that upstream's trivial changes to the MUMPS Conditions of Use don't make them a different license * licenses.txt, *.c, *.h: allow linking with code under the Eclipse Public License, used by current versions of Ipopt 2007-11-15 Release 1 * initial release as documented in my diploma thesis