#!/usr/bin/env python3

# bbowda - Black Box Optimization With Data Analysis
# Copyright (C) 2006-2024 Kevin Kofler <Kevin@tigcc.ticalc.org>
# 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/>.

import bbowda

# USER INPUT: Problem dimensions
DIMX = 2 # scale this to scale the problem
DIMY = 1
DIMY_EQ = 0

# USER INPUT: Number of starting points
NUMINITPTS = 0

#USER INPUT:
# min cT (x, F(x))
c = [0. for i in range(DIMX)] + [1. for i in range(DIMY)]
# s.t. Flow <= F(x) <= Fup
Flow=[-1000. for i in range(DIMY)]
Fup=[2700. for i in range(DIMY)]
#      xlow <= x <= xup
xlow=[-1. for i in range(DIMX)]
xup=[2. for i in range(DIMX)]

# starting points
initpts=[] if NUMINITPTS>0 else None

# USER INPUT: Maximum points to evaluate
MAXPTS = 200

# USER INPUT: Tolerance for optimum feasibility
OPTIMUM_TOL = .001

# USER INPUT: If True, ignore equality constraints for global search
GLOBAL_SEARCH_IGNORES_EQ_CONSTRAINTS = False

# USER INPUT: Tolerance for the constraints estimating the equality constraints
#             during global search
ESTIMATE_CONSTRAINT_TOL = .01

class Problem(bbowda.OptimizationProblem):
  def __init__(self):
    bbowda.OptimizationProblem.__init__(self, DIMX, DIMY, DIMY_EQ, NUMINITPTS,
                                        c, xlow, xup, Flow, Fup, initpts)

  # evaluate F(x)
  def evaluateF(self, x, F):
    F[0] = 0.
    for i in range(DIMX - 1):
      F[0] += (1. - x[i]) * (1. - x[i]) + 100. * (x[i+1] - x[i]*x[i]) * (x[i+1] - x[i]*x[i])

# ensure reproducible results
bbowda.srand(31337)

# initialize and/or allocate problem, if necessary
problem = Problem()

# run the optimization
problem.solve(bbowda.SolverParameters(MAXPTS, OPTIMUM_TOL,
                                      GLOBAL_SEARCH_IGNORES_EQ_CONSTRAINTS,
                                      ESTIMATE_CONSTRAINT_TOL))
