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 392 forks source link

Discrete sampling in multiples of two. #197

Closed Atulsingh92 closed 3 years ago

Atulsingh92 commented 3 years ago

Hello Julian,

I had a question about sampling the discrete variable problem only in multiples of a number. This is becuase I am trying to solve a heat exchanger problem, which has "number of passes", basically the the flow of fluid going form one pass to another, before it exits the system. Essentially, this variable cannot be odd for the design I am working on.

def __init__(self):
        super().__init__(n_var = 4,
                         n_obj = 1,
                         n_constr = 5,             
                         xl = anp.array([26, 17, 2, 525]), # Number of pass is 2<Np<8, and 2, 4, 6, 8 are only permissible
                         xu = anp.array([32, 34, 8, 788]),
                         )

Ofcourse, the best result right now comes with 3 number of passes! Any suggestions on how can I set this up?

blankjul commented 3 years ago

Change the variable mapping. Let the variable be in the range of 1 to 4. Then in the _evaluate function, you multiple the value by two, which always makes it an even number.

Another way is adding a constraint out["G"] to your problem. The remapping is smarter in your case.

I also have to say the discrete GA was easy to create because of the modular implementation of pymoo. However, I have not yet run extensive benchmarks on it. Also, you might want to do some experiments with the eta variable of SBX and PM if you use them.

Atulsingh92 commented 3 years ago

If I understand correctly , you mean,

    def __init__(self):
        super().__init__(n_var = 4,
                         n_obj = 1,
                         n_constr = 5,             
                         xl = anp.array([26, 17, 1, 525]), 
                         xu = anp.array([32, 34, 4, 788]),
                         )

and then use it as

Np = 2*x[:,2] also Np = (x[:,2]/2).astype(int) # for 2<x[:,2]<8

with

algorithm = NSGA2(
        pop_size = population_size, 
        n_offsprings = 40,
        sampling = get_sampling("int_lhs"),
        crossover = get_crossover("int_sbx", prob = 0.9, eta = 3.0),
        mutation = get_mutation("int_pm", eta=3.0),
        eliminate_duplicates = True
        )

gives the following result

In [26] : res.history[0].pop.get("X")
Out[26]: 
array([[ 26,  17,   2, 761],
       [ 27,  17,   4, 736],
       [ 26,  18,   3, 567],
       [ 28,  17,   1, 659],
       [ 28,  17,   3, 582],
       [ 28,  17,   4, 742],

No joy!

blankjul commented 3 years ago

Is that not what you wanted?

If you multiple now the third column by two this is your remapped solutions. To have this directly, in the problem's _evaluate function set out["__X__"] = mapped(x) and then access the true function values by pop.get("__X__") when the run is over.

Atulsingh92 commented 3 years ago

Well, like I mentioned, only even number are permissible. So, needed 2, 4, 6, 8 instead!

blankjul commented 3 years ago

You do! Because 1 -> 2, 2 -> 4, 3 -> 6, 4 -> 8

It is just a simple remapping.

Atulsingh92 commented 3 years ago

Can you also give an example of setting this with constraints?

blankjul commented 3 years ago

Redefine the problem, set n_constr=1. Make the constraint out["G"] to be 1 if infeasible (odd) and 0 otherwise (even).