pymoo icon indicating copy to clipboard operation
pymoo copied to clipboard

The repair is not passed to the mating argument of the MixedVariableGA class

Open xinwang0312 opened this issue 1 year ago • 5 comments

Not sure whether this is by design, suppose I want to have a customized repair for MixedVariableGA. But this customized repair is not passed to the mating argument https://github.com/anyoptimization/pymoo/blob/af8d260a5ba34c5e427b671586c32351765419a9/pymoo/core/mixed.py#L160

As a consequence, the mated population may not follow the constraints defined in the customized repair unless it is specifically passed such as

mating=MixedVariableMating(eliminate_duplicates=MixedVariableDuplicateElimination(), repair=some_repair())

xinwang0312 avatar Mar 08 '24 15:03 xinwang0312

Without having tried it myself, repair is a paramter of MixedVariableMating. Can you check if passing it here works for you?

blankjul avatar Mar 16 '24 19:03 blankjul

@blankjul Yes, actually it is what I mean and it took me sometime to figure out. The customized repair not only has to be passed for the MixedVariableGA itself, but also has to be explicitly passed to MixedVariableMating.

So the initialization of a MixedVariableGA with a customized repaire would be something like below, which is not very handy to use.

algo = MixedVariableGA(
    ..., 
    mating=MixedVariableMating(eliminate_duplicates=MixedVariableDuplicateElimination(), repair=some_repair()),
    repair=some_repair()
   )

If it is not by design, maybe we can consider to first check whether repair is in the kwargs, if it is, then also "add" it to the mating?

xinwang0312 avatar Mar 19 '24 21:03 xinwang0312

This actually is by design. The main reason is that the mating creates n individuals which are not duplicated with the population passed AND within itself. To determine if an indvidual is a duplicate we first have to run the Repair operator. Otherwise, it might not be a duplicate initially, but then become one after the repair operator has been applied.

I was thinking about this statement

The customized repair not only has to be passed for the MixedVariableGA itself, but also has to be explicitly passed to MixedVariableMating.

Does this imply if you DO NOT pass it to MixedVariableGA it does not work? I would think ONLY passing it to MixedVariableMating should be sufficient. Can you quickly check if this is the case?

blankjul avatar Mar 23 '24 16:03 blankjul

Hi @blankjul , sorry for the late reply. No, only passing the repair to the mating does not work. I have a minimum working example based on https://pymoo.org/customization/mixed.html to reproduce the test.

My pymoo version is 0.6.1.1.

So I want to apply a simple constraint to force x['b'] + x['y'] + x['z'] = 5

  1. if I only pass the repair to the algorithm, the constraint only holds for the first iteration and then breaks
  2. if I both pass the repair to the algorithm and the mating, the constraint only holds, which is desired
  3. if I only pass the repair to the mating, I got a warning "WARNING: Mating could not produce the required number of (unique) offsprings!"

I hope this is enough for you to reproduce the test and let me know if you need anything else.

from pymoo.core.mixed import (
    MixedVariableDuplicateElimination,
    MixedVariableGA,
    MixedVariableMating,
)
from pymoo.core.problem import ElementwiseProblem
from pymoo.core.repair import Repair
from pymoo.core.variable import Binary, Choice, Integer, Real
from pymoo.optimize import minimize


class MixedVariableProblem(ElementwiseProblem):

    def __init__(self, **kwargs):
        vars = {
            "b": Binary(),
            "x": Choice(options=["nothing", "multiply"]),
            "y": Integer(bounds=(0, 2)),
            "z": Real(bounds=(0, 5)),
        }
        super().__init__(vars=vars, n_obj=1, **kwargs)

    def _evaluate(self, X, out, *args, **kwargs):
        b, x, z, y = X["b"], X["x"], X["z"], X["y"]

        f = z + y
        if b:
            f = 100 * f

        if x == "multiply":
            f = 10 * f

        out["F"] = f


class ToyRepair(Repair):
    def _do(self, problem, X, **kwargs):
        return [self._repair_z(x) for x in X]

    @staticmethod
    def _repair_z(x):
        x["z"] = 5 - x["b"] - x["y"]
        return x


problem = MixedVariableProblem()

# algorithm = MixedVariableGA(pop=10, repair=ToyRepair()) # constraint does not hold
mating = MixedVariableMating(
    eliminate_duplicates=MixedVariableDuplicateElimination(), repair=ToyRepair()
)
# algorithm = MixedVariableGA(
#     pop=10, mating=mating, repair=ToyRepair()
# )  # constraint hold

# WARNING: Mating could not produce the required number of (unique) offsprings!
algorithm = MixedVariableGA(pop=10, mating=mating)


res = minimize(problem, algorithm, termination=("n_evals", 1000), seed=1, verbose=True)

print("Best solution found: \nX = %s\nF = %s" % (res.X, res.F))

xinwang0312 avatar Mar 27 '24 16:03 xinwang0312

Fair point! I have just checked the code and can reproduce it!

In fact, not passing it will make the initial population to be non-repaired. But all individuals will be repaired later on! Do you have any direct suggestion how you would expect this to be improved? Happy to look at a PR as well.

blankjul avatar Apr 10 '24 02:04 blankjul