1

I am trying to follow this method to solve an optimization problem. I have a bag of N=100 vehicles which have certain properties. For example cost, rank, and mpg. I am looking to find k=5 subsets of vehicles that have higher mpg and rank than others. N and k can take any values.

Following the pymoo, the evaluation function looks like this:

    def _evaluate(self, x, out, *args, **kwargs):
        out["F"] = np.array([x["rank"], x["mpg"]], dtype=float)

Here, x has as many dimensions as many columns for vehicles. In this case, I am using rank and mpg as I want to maximize these.

The guide says to create methods including:

Sampling Crossover Mutation

I want to know how can I formulate the above problem in these functions.

  1. Sampling: refer the link above, should I create a method that takes 5 random vehicles from bag and return these?
  2. Crossover: I am blind to this. What should I be doing in my case?
  3. Mutation: I don't know what to implement here.

If somebody has used pymoo, give me some hints on the above so that I can do my implementation.

Many Thanks

*** Here is the updated code for now. I am getting an error (attached).Error

from pymoo.algorithms.soo.nonconvex.ga import GA
from pymoo.optimize import minimize
from pymoo.core.crossover import Crossover
from pymoo.core.mutation import Mutation
from pymoo.core.sampling import Sampling
import numpy as np
from pymoo.core.problem import ElementwiseProblem

class SubsetProblem(ElementwiseProblem):
    def __init__(self,L,n_max):
        super().__init__(n_var=len(L), n_obj=2, n_ieq_constr=0)
        self.L = L
        self.n_max = n_max

    def _evaluate(self, x, out, *args, **kwargs):
        out["F"] = np.array([self.L[x][0], self.L[x][1]], dtype=float)
        #out["G"] = (self.n_max - np.sum(x)) ** 2
        

class MySampling(Sampling):

    def _do(self, problem, n_samples, **kwargs):
        X = np.full((n_samples, problem.n_var), False, dtype=bool)

        for k in range(n_samples):
            I = np.random.permutation(problem.n_var)[:problem.n_max]
            X[k, I] = True

        return X

class BinaryCrossover(Crossover):
    def __init__(self):
        super().__init__(2, 1)

    def _do(self, problem, X, **kwargs):
        n_parents, n_matings, n_var = X.shape

        _X = np.full((self.n_offsprings, n_matings, problem.n_var), False)

        for k in range(n_matings):
            p1, p2 = X[0, k], X[1, k]

            both_are_true = np.logical_and(p1, p2)
            _X[0, k, both_are_true] = True

            n_remaining = problem.n_max - np.sum(both_are_true)

            I = np.where(np.logical_xor(p1, p2))[0]

            S = I[np.random.permutation(len(I))][:n_remaining]
            _X[0, k, S] = True

        return _X


class MyMutation(Mutation):
    def _do(self, problem, X, **kwargs):
        for i in range(X.shape[0]):
            X[i, :] = X[i, :]
            is_false = np.where(np.logical_not(X[i, :]))[0]
            is_true = np.where(X[i, :])[0]
            X[i, np.random.choice(is_false)] = True
            X[i, np.random.choice(is_true)] = False

        return X

# create the actual problem to be solved
np.random.seed(1)
L = np.array([[9,13],[9,14],[7,15],[6,12],[8,16],[8,14],[6,12],[3,18],[4,14],[5,14],[8,11],[8,18]])
n_max = 3
problem = SubsetProblem(L, n_max)


algorithm = GA(
    pop_size=12,
    sampling=MySampling(),
    crossover=BinaryCrossover(),
    mutation=MyMutation(),
    eliminate_duplicates=True)

res = minimize(problem,
               algorithm,
               ('n_gen', 60),
               seed=1,
               verbose=True)

print("Function value: %s" % res.F[0])
print("Subset:", np.where(res.X)[0])

1 Answers1

0

There are different ways you can formulate a subset selection problem. You can find a tutorial in the pymoo documentation as well: https://pymoo.org/case_studies/subset_selection.html

There, the binary variables are used and suitable operators are implemented. I think the example provided there should be directly applicable to your problem.

Julian
  • 416
  • 1
  • 4
  • 8
  • Hi - Thanks for quick contact. I am following that example. I want to know if I can use a two dimensional array in place of 'L' there? I also don't get why len(L) stands for n_var in INIT. here, I have two variables in my array. something like this: L = np.array([[9,13],[9,14],[7,15],[6,12],[8,16],[8,14],[6,12],[3,18],[4,14],[5,14],[8,11],[8,18]]) – rockstone435 Mar 21 '23 at 02:54
  • You can also define a bi-objective optimization problem. Looks to me like you want to do that. Just set to `out["F"]` a list of size two. You can use `L[x].sum(axis=0)`. – Julian Mar 22 '23 at 04:15