/* bbowdapp - C++ binding for bbowda
   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 "bbowdapp_export.h"

#include "bbowda.h"

#include <cstddef>

namespace Bbowda {
  /**
   * @brief Solver parameters for the BBOWDA algorithm.
   *
   * Parameters allowing to tune how the BBOWDA algorithm operates.
   */
  class BBOWDAPP_EXPORT SolverParameters : public bbowda_params {
    public:
      /**
       * @brief Constructor.
       *
       * @param maxpts Maximum number of points to evaluate. See @ref maxpts.
       * @param optimum_tol Tolerance for optimum feasibility (infinity norm).
       *                    See @ref optimum_tol.
       * @param global_search_ignores_eq_constraints Whether to ignore implicit
       *   equality constraints for global search. See
       *   @ref global_search_ignores_eq_constraints.
       * @param estimate_constraint_tol Tolerance for the constraints estimating
       *                                the implicit equality constraints during
       *                                global search. See
       *                                @ref estimate_constraint_tol.
       */
      SolverParameters(size_t maxpts, double optimum_tol,
                       bool global_search_ignores_eq_constraints,
                       double estimate_constraint_tol);
  };

  /**
   * @brief Definition of a black box optimization problem.
   *
   * This class represents both the constants (inherited from
   * @ref bbowda_problem) and the black box function (in the form of the pure
   * virtual method @ref evaluateF) that together represent the black box
   * optimization problem. Subclass this class to implement your 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
   */
  class BBOWDAPP_EXPORT OptimizationProblem : public bbowda_problem {
    public:
      /**
       * @brief Main constructor.
       *
       * @param dimx Number of input variables. See @ref dimx.
       * @param dimy Number of explicit equality constraints. See @ref dimy.
       * @param dimy_eq Number of implicit equality constraints. See
       *                @ref dimy_eq.
       * @param numinitpts Number of user-specified starting points. See
       *                   @ref numinitpts.
       * @param c Coefficients in the (linear) objective function. See @ref c.
       * @param xlow Lower bounds for input variables. See @ref xlow.
       * @param xup Upper bounds for input variables. See @ref xup.
       * @param Flow Lower bounds for explicit equality constraints. See
       *             @ref Flow.
       * @param Fup Upper bounds for explicit equality constraints. See
       *            @ref Fup.
       * @param initpts_p User-provided starting points. See @ref initpts_p.
       * @param copyVectors Whether to copy the vectors.
       */
      OptimizationProblem(int dimx, int dimy, int dimy_eq, int numinitpts,
                          const double *c, const double *xlow,
                          const double *xup, const double *Flow,
                          const double *Fup, const double *initpts_p,
                          bool copyVectors=true);

#if __cplusplus >= 201103L // delegating constructors not available below C++11
      /**
       * @brief Convenience constructor.
       *
       * This template constructor is syntactic sugar allowing to pass a
       * 2-dimensional array as @a initpts directly, without having to
       * explicitly write <c>&initpts[0][0]</c>.
       *
       * @param dimx Number of input variables. See @ref dimx.
       * @param dimy Number of explicit equality constraints. See @ref dimy.
       * @param dimy_eq Number of implicit equality constraints. See
       *                @ref dimy_eq.
       * @param numinitpts Number of user-specified starting points. See
       *                   @ref numinitpts.
       * @param c Coefficients in the (linear) objective function. See @ref c.
       * @param xlow Lower bounds for input variables. See @ref xlow.
       * @param xup Upper bounds for input variables. See @ref xup.
       * @param Flow Lower bounds for explicit equality constraints. See
       *             @ref Flow.
       * @param Fup Upper bounds for explicit equality constraints. See
       *            @ref Fup.
       * @param initpts User-provided starting points as a 2-dimensional array.
       *                Should be of type <c>double[numinitpts][dimx]</c>. See
       *                @ref initpts_p.
       * @param copyVectors Whether to copy the vectors.
       */
      template<std::size_t n> OptimizationProblem(int dimx, int dimy,
                                                  int dimy_eq, int numinitpts,
                                                  const double *c,
                                                  const double *xlow,
                                                  const double *xup,
                                                  const double *Flow,
                                                  const double *Fup,
                                                  const double (*initpts)[n],
                                                  bool copyVectors=true)
        : OptimizationProblem(dimx, dimy, dimy_eq, numinitpts, c, xlow, xup,
                              Flow, Fup, &initpts[0][0], copyVectors) {}
#endif

      /**
       * @brief Virtual destructor.
       */
      virtual ~OptimizationProblem();

      /**
       * @brief Main entry point of the BBOWDA C++ API.
       *
       * Runs the BBOWDA algorithm on this problem with the given parameters.
       *
       * Object-oriented wrapper around the C API entry point @ref bbowda.
       *
       * @param params The solver parameters for the BBOWDA algorithm.
       */
      void solve(const SolverParameters &params);
    protected:
      /**
       * @brief Pure virtual callback evaluating the black box function.
       *
       * Callback evaluating the black box function (or obtaining the evaluation
       * result from an external source) at the point @a x (of dimension
       * @ref dimx) and writing the result to @a F (of dimension @ref dimy +
       * @ref dimy_eq). Must be implemented by the user through subclassing.
       *
       * @note There is no @a user_data pointer because any user data can and
       * should be included in the user-provided subclass.
       */
      virtual void evaluateF(const double *x, double *F) = 0;
    private:
      // Private C-compatible wrapper for the C++ callback. Not part of the API!
      BBOWDAPP_NO_EXPORT
      static void evaluate_F_cb(const struct bbowda_problem *problem,
                                const double *x, double *F, void *user_data);
      bool m_freeVectors;
  };
}
