Example

Here is an example of a simple constrained discrete problem, solved using a genetic algorithm:

from pathlib import Path
import numpy as np
from ropt.evaluator import EvaluatorResult
from ropt.plan import BasicOptimizer
from ruamel import yaml

# For convenience we use a YAML file to store the optimizer options:
options = yaml.YAML(typ="safe", pure=True).load(Path("options.yml"))

CONFIG = {
    "variables": {
        # Ignored, but needed to establish the number of variables:
        "initial_values": 2 * [0.0],
        "lower_bounds": [0.0, 0.0],
        "upper_bounds": [10.0, 10.0],
    },
    "optimizer": {
        "method": "soo.nonconvex.ga.GA",
        "options": options,
    },
    "nonlinear_constraints": {"lower_bounds": [-np.inf], "upper_bounds": [0.0]},
}

def function(variables, _):
    x, y = variables[0, :]
    objectives = np.array(-min(3 * x, y), ndmin=2, dtype=np.float64)
    constraints = np.array(x + y - 10, ndmin=2, dtype=np.float64)
    return EvaluatorResult(objectives=objectives, constraints=constraints)

optimal_result = BasicOptimizer(CONFIG, function).run().results
print(f"Optimal variables: {optimal_result.evaluations.variables}")
print(f"Optimal objective: {optimal_result.functions.weighted_objective}")

To run, first create a YAML file called options.yml with the following contents:

parameters:
  pop_size: 20
  sampling:
    object: operators.sampling.rnd.IntegerRandomSampling
  crossover:
    object: operators.crossover.sbx.SBX
    parameters:
      prob: 1.0
      eta: 3.0
      vtype: float
      repair:
        object: operators.repair.rounding.RoundingRepair
  mutation:
    object: operators.mutation.pm.PM
    parameters:
      prob: 1.0
      eta: 3.0
      vtype: float
      repair:
        object: operators.repair.rounding.RoundingRepair
  eliminate_duplicates: True

termination:
  name: max_gen.MaximumGenerationTermination
  parameters:
    n_max_gen: 10

constraints:
  name: as_penalty.ConstraintsAsPenalty
  parameters:
    penalty: 100.0

seed: 1234

Running this will output the following:

$ python example.py
=================================================
n_gen  |  n_eval  |     f_avg     |     f_min    
=================================================
     1 |       18 |  1.740556E+02 | -6.000000E+00
     2 |       38 | -2.300000E+00 | -6.000000E+00
     3 |       58 | -3.600000E+00 | -6.000000E+00
     4 |       78 | -4.400000E+00 | -7.000000E+00
     5 |       98 | -4.450000E+00 | -7.000000E+00
     6 |      118 | -4.500000E+00 | -7.000000E+00
     7 |      138 | -4.600000E+00 | -7.000000E+00
     8 |      158 | -4.600000E+00 | -7.000000E+00
     9 |      178 | -4.600000E+00 | -7.000000E+00
    10 |      198 | -4.600000E+00 | -7.000000E+00
Optimal variables: [3. 7.]
Optimal objective: -7.0