anyoptimization / pymoo

NSGA2, NSGA3, R-NSGA3, MOEAD, Genetic Algorithms (GA), Differential Evolution (DE), CMAES, PSO
https://pymoo.org
Apache License 2.0
2.28k stars 390 forks source link

Binary random sampling, vtype = bool in problem class, optimizer changes solution x from boolean to float after first iteration #496

Closed juanlu29 closed 11 months ago

juanlu29 commented 12 months ago

I am using Pymoo for a research project in academia. In particular I am working in a bi-objective optimization problem using a binary description of the solution. I am particularly interested in using NSGA-ii algorithm. This is my problem._evaluate() method,


 def _evaluate(self, x, out, *args, **kwargs):

        populationSize = x.shape[0]
        numberIgnitions = self.arrivalTimes.shape[0]
        numberSensors = self.arrivalTimes.shape[1]
        integerX = np.zeros((populationSize,numberSensors),dtype=int)
        integerX[x==True] = 1

        f1 = np.zeros((populationSize))
        for p in range(populationSize):
            minimumTimes = np.zeros(numberIgnitions)
            for i in range(numberIgnitions):
                s = 0
                while not (x[p,self.sorting[i,s]]):
                    if s == numberSensors-1:
                        break
                    else:
                        s += 1
                minimumTimes[i] = self.arrivalTimes[i,self.sorting[i,s]]

            f1[p] = np.sum(minimumTimes) 

        f2 = np.sum(integerX, axis=1) # integer x does not depend on ignition
        f1[np.where(f2==0.)[0]] = nIgnitions*5*3600 # When f2 objective is null, it is necessary to give penalization

        out["F"] = np.column_stack([f1, f2])

The problem we have encountered is that x, after the first iteration of this _evaluate function, is not boolean anymore. Apparently the optimizer converts it from boolean variable to float, thus translating true/false into 0.99 or 0.001 values. This further fluctuate, making the optimization futile. A very simple patch can be provided if I include an statement x = x>0.5 (masking my own solution values). Is it right that pymoo converts x from boolean (the first iteration it is boolean) and later into float?.

Some more details of my implementation, this is how i run the optimization,


algorithm = NSGA2(
   pop_size=npop,
    n_offsprings=nOffsprings,
    sampling=BinaryRandomSampling(),
    crossover=SBX(prob=0.9, eta=15),
    mutation=PM(eta=25),
    eliminate_duplicates=True
)
  res = minimize(problem_s,
              algorithm,
              termination,
              seed = 1,
              verbose=True)

And this is how I define my problem class,


class Sensor_while(Problem):
    def __init__(self,
                 n_sensor,   # number of sensors to deploy
                 arrivalTimes,   # fire data, arrival times at ignition locations (rows) per sensor locations (columns). Broadcasted to pop size
                 sorting      # Empty array with structure of expected population sample of solution during optimization. Broadcasted to fit number of ignitions
                 ):

        super().__init__(n_var=n_sensor, n_obj=2, n_ieq_constr=0, xl=0, xu=1, vtype=bool)

Thanks a lot for building this nice library and giving us this channel to communicate.

Juan Luis

blankjul commented 12 months ago

You can not use SBX if you want to solve a binary problem. checkout the tutorial for binary optimization: https://pymoo.org/customization/binary.html

Does this work for you?

juanlu29 commented 11 months ago

Hi,

This actually provides for a lot of help in my work. I did not check carefully that example in the tutorial. After performing several tests, this completely solves my issue.

Thanks a lot Juanlu