/* bbowda - Black Box Optimization With Data Analysis
   Copyright (C) 2025 DAGOPT Optimization Technologies GmbH (www.dagopt.com)
                      written by Kevin Kofler <kofler@dagopt.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version. A copy of the GNU General Public
   License version 3 can be found in the file gpl-3.0.txt.

   Linking bbowda statically or dynamically (directly or indirectly) with
   other modules is making a combined work based on bbowda. Thus, the terms
   and conditions of the GNU General Public License cover the whole
   combination.

   In addition, as a special exception, the copyright holder of bbowda gives
   you permission to combine the bbowda program:
   * with free software programs or libraries that are released under the
     GNU Library or Lesser General Public License (LGPL), either version 2
     of the License, or (at your option) any later version,
   * with free software programs or libraries that are released under the
     IBM Common Public License (CPL), either version 1.0 of the License, or
     (at your option) any later version,
   * with free software programs or libraries that are released under the
     eclipse.org Eclipse Public License (EPL), either version 1.0 of the
     License, or (at your option) any later version,
   * with free software programs or libraries that are released under the
     CeCILL-C Free Software License Agreement, either version 1 of the License,
     or (at your option) any later version,
   * with code included in the standard release of MUMPS under the old MUMPS
     Conditions of Use as reproduced in licenses.txt (or modified versions
     of such code, with unchanged license; variants of the license where only
     the list of contributors and/or the list of suggested citations changed
     shall be considered the same license) and
   * if you qualify for a free of charge license of DONLP2, with code
     included in the standard release of DONLP2 under the DONLP2 Conditions
     of Use as reproduced in licenses.txt (or modified versions of such code,
     with unchanged license).
   (For avoidance of doubt, this implies that it is permitted, e.g., to combine
   the bbowda program with current versions of Ipopt released under the EPL
   version 2.0, because 2.0 is >= 1.0. Its dependency MUMPS is released under
   the CeCILL-C version 1, which is also listed above.)

   You may copy and distribute such a system following the terms of the GNU
   GPL for bbowda and the licenses of the other code concerned, provided that
   you include the source code of that other code when and as the GNU GPL
   requires distribution of source code.

   Note that people who make modified versions of bbowda are not obligated
   to grant this special exception for their modified versions; it is their
   choice whether to do so. The GNU General Public License gives permission
   to release a modified version without this exception; this exception also
   makes it possible to release a modified version which carries forward
   this exception.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>. */

#pragma once

#include "bbowda_export.h"

#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @mainpage
 *
 * @section introduction Introduction
 *
 * BBOWDA is an algorithm and a reference implementation to solve optimization
 * problems where:
 *
 * * both the objective function and the constraints may be black box functions,
 * * we do not have any gradient or Hessian information for those black box
 *   functions,
 * * the functions are assumed to be expensive to compute, thus the number of
 *   function evaluations shall be kept as small as possible,
 *
 * using methods from data analysis:
 *
 * * covariance models,
 * * Gaussian mixture models (GMMs) and the Expectation-Maximization (EM)
 *   iteration, and
 * * ratio-reject (outlier rejection algorithm by Tax and Duin).
 *
 * The algorithm is a so-called incomplete global optimizer, i.e. it attempts to
 * find a global solution for the optimization problem, but is unable to
 * guarantee globality. In fact, it cannot even guarantee always finding a local
 * optimum, due to the lack of gradients and any sort of global information.
 * Despite this lack of guarantees, the algorithm performs well in practice.
 *
 * BBOWDA is a surrogate model method, hence it depends on third-party solvers
 * for Non-Linear (optimization) Programs (NLPs) and Linear (optimization)
 * Programs (LPs).
 *
 * For NLPs, BBOWDA currently supports any of:
 *
 * * NLopt SLSQP (MIT and 3-clause BSD licenses),
 * * Ipopt from COIN-OR (Eclipse Public License version 2.0),
 * * DONLP2 (donlp2_intv_dyn) by Prof. Peter Spellucci (free for research only),
 * * DONLP3 (reentrant C++ version of DONLP2, see above, from COCONUT).
 *
 * Note that DONLP2 is NOT reentrant. Use another solver if you require BBOWDA
 * to be reentrant. All other currently supported solvers (including DONLP3) are
 * reentrant.
 *
 * For LPs, BBOWDA currently requires lp_solve (GNU LGPL version 2.1 or later).
 *
 * The implementation is licensed under the GNU General Public License, version
 * 3 or later, with special exceptions allowing to link with the third-party
 * optimizers used. See licenses.txt for details.
 *
 * @section apidoc API Documentation
 *
 * This documentation documents the public C and C++ API of BBOWDA.
 *
 * @subsection apidoc_c C API (Procedural API)
 *
 * See @ref bbowda.h. The main entry point is @ref bbowda.
 *
 * @subsection apidoc_cc C++ API (Object-oriented API)
 *
 * See @ref bbowdapp/bbowdapp.hh. The main entry point is
 * @ref Bbowda::OptimizationProblem::solve.
 */

/**
 * @brief Constants that, together with the black box function, define a black
 *        box optimization problem.
 *
 * The problem is assumed to be of the form:
 * @code{.unparsed}
 * min cT (x ; y)
 * s.t. y = F1(x) [explicit equality constraints]
 *      F2(x) = 0 [implicit equality constraints]
 *      xlow <= x <= xup
 *      Flow <= y <= Fup
 * @endcode
 */
struct bbowda_problem {
  /**
   * @brief Number of input variables.
   *
   * The vector dimension of @a x.
   */
  int dimx;

  /**
   * @brief Number of explicit equality constraints.
   *
   * The vector dimension of @a y = F1(@a x). Also known as the number of
   * interval inequality constraints if the coefficients of @a y in @ref c are
   * 0.
   */
  int dimy;

  /**
   * @brief Number of implicit equality constraints.
   *
   * Vector dimension of F2(@a x).
   */
  int dimy_eq;

  /**
   * @brief Number of user-specified starting points.
   *
   * Can be 0. If no or not enough starting points are provided by the user,
   * BBOWDA will automatically sample some starting points within the bounds.
   */
  int numinitpts;


  /**
   * @brief Coefficients in the (linear) objective function.
   *
   * The coefficient vector @a c. Must have dimension @ref dimx + @ref dimy.
   * First list all coefficients of @a x in order, then all coefficients of
   * @a y = F1(@a x) in order.
   */
  const double *c;

  /**
   * @brief Lower bounds for input variables.
   *
   * Lower bounds for @a x. Must have dimension @ref dimx.
   */
  const double *xlow;

  /**
   * @brief Upper bounds for input variables.
   *
   * Upper bounds for @a x. Must have dimension @ref dimx.
   */
  const double *xup;

  /**
   * @brief Lower bounds for explicit equality constraints.
   *
   * Lower bounds for @a y = F1(@a x). Must have dimension @ref dimy.
   *
   * @note No bounds need to be specified for the implicit equality constraints
   * F2(@a x) because those bounds are by definition always 0.
   */
  const double *Flow;

  /**
   * @brief Upper bounds for explicit equality constraints.
   *
   * Upper bounds for @a y = F1(@a x). Must have dimension @ref dimy.
   *
   * @note No bounds need to be specified for the implicit equality constraints
   * F2(@a x) because those bounds are by definition always 0.
   */
  const double *Fup;

  /**
   * @brief User-provided starting points.
   *
   * Must be a contiguous matrix of dimension @ref numinitpts * @ref dimx (in
   * row-major order, i.e., first all components of the first starting point,
   * then the second one, etc.). If @ref numinitpts is 0, this is just an empty
   * vector (and can be NULL). Otherwise, it can be a pointer of the form
   * <c>&initpts[0][0]</c>, where @a initpts is defined as
   * <c>double initpts[numinitpts][dimx]</c>. (In
   * fact, that will work in practice even if @ref numinitpts is 0 because C
   * allows pointers to the end of an array.)
   */
  const double *initpts_p;
};

/**
 * @brief Solver parameters for the BBOWDA algorithm.
 *
 * Parameters allowing to tune how the BBOWDA algorithm operates.
 */
struct bbowda_params {
  /**
   * @brief Maximum number of points to evaluate.
   *
   * Currently, the algorithm will always run until exactly this many points are
   * evaluated, because no other stopping criteria are implemented yet. In the
   * presence of implicit equality constraints, it may then evaluate one more
   * point for the final extrapolation attempt.
   */
  size_t maxpts;

  /**
   * @brief Tolerance for optimum feasibility (infinity norm).
   *
   * A point will be considered feasible, and thus a valid candidate for the
   * optimum, if the bound constraints for @a x are satisfied exactly, and if
   * none of the other constraints is violated by more than @a optimum_tol,
   * i.e., if the componentwise inequalities @a Flow - @a optimum_tol <=
   * F1(@a x) <= @a Fup + @a optimum_tol and - @a optimum_tol < F2(@a x) <
   * @a optimum_tol hold. In vector terms, this means that the infinity norm of
   * the constraint violation must be less than @a optimum_tol.
   */
  double optimum_tol;

  /**
   * @brief Whether to ignore implicit equality constraints for global search.
   *
   * A true (non-zero) value means that implicit equality constraints will be
   * ignored by the global search. Hence, it will suggest evaluation points to
   * fill any gaps in the search space even if they are nowhere near feasible
   * for the implicit equality constraints.
   *
   * The false (zero) value means that implicit equality constraints will be
   * honored by the global search. The global search will compute estimates that
   * attempt to globally enclose the implicit equality constraints with the help
   * of an external LP solver, helping to suggest only points that are expected
   * to be approximately feasible.
   *
   * This parameter has no effect if the problem does not include any implicit
   * equality constraints.
   */
  int global_search_ignores_eq_constraints;

  /**
   * @brief Tolerance for the constraints estimating the implicit equality
   *        constraints during global search.
   *
   * If @ref global_search_ignores_eq_constraints is false (zero), the global
   * search attempts to estimate global enclosures for the implicit equality
   * constraints. But those enclosures are estimated approximations and not
   * guaranteed to hold exactly. This tolerance specifies by how much the bounds
   * for the estimated enclosures should be relaxed to account for that.
   *
   * This parameter has no effect if the problem does not include any implicit
   * equality constraints or if @ref global_search_ignores_eq_constraints is
   * true (non-zero).
   */
  double estimate_constraint_tol;
};

/**
 * @brief Main entry point of the BBOWDA C API.
 *
 * Runs the BBOWDA algorithm on the given problem with the given parameters.
 *
 * @param problem The constants that, together with the black box function,
 *                define the problem.
 * @param params The solver parameters for the BBOWDA algorithm.
 * @param evaluate_F Function pointer to the callback evaluating the black box
 *                   function (or obtaining the evaluation result from an
 *                   external source) at the point @a x (of dimension
 *                   @ref bbowda_problem::dimx) and writing the result to @a F
 *                   (of dimension @ref bbowda_problem::dimy +
 *                   @ref bbowda_problem::dimy_eq).
 * @param eval_user_data Pointer that will be passed unchanged as @a user_data
 *                       to all invocations of @a evaluate_F.
 */
BBOWDA_EXPORT void bbowda(const struct bbowda_problem *problem,
                          const struct bbowda_params *params,
                          void (*evaluate_F)
                                 (const struct bbowda_problem *problem,
                                  const double *x, double *F, void *user_data),
                          void *eval_user_data);

#ifdef __cplusplus
}
#endif
