esa / pagmo

A C++ / Python platform to perform parallel computations of optimisation tasks (global and local) via the asynchronous generalized island model. State of the art optimization algorithms are included. A common interface is provided to other optimization frameworks/algorithms such as NLOPT, SciPy, SNOPT, IPOPT, GSL
GNU General Public License v3.0
268 stars 87 forks source link

DEA on custom model with cost parametrized function #192

Open mdepitta opened 7 years ago

mdepitta commented 7 years ago

I am trying to use differential evolution for a problem where the function to minimize is of the form f(x,p) where x is the vector of constrained variables to change during evolution to optimize f, and p is a vector of parameters.

I need to perform optimization of "f" for different parameter vectors p1,..., pN.

There is a problem however in passing every time different parameter vectors. the class definition of my problem specify some defaults for "p". Say p=p1. If I run a for-loop over different parameter vectors, it turns out that p_i -- the parameter vector at the i-th step of the loop -- is passed only initially to the problem, but then at successive (internal) calls of my problem class by island.evolve, p returns to be p1, that is the default.

Take for example:

import PyGMO as pygmo

class my_problem(pygmo.problem.base):
    def __init__(self, par1 = 10.):
        self.__dim = 10
        self.p1 = par1
        print self.p1
        super(my_problem,self).__init__(self.__dim)
        self.set_bounds(-5.12,5.12)

    def _objfun_impl(self,x):
        f = 0
        for i in range(self.__dim):
            f = f + (x[i]/self.p1)*(x[i])
        return (f,)
if __name__=="__main__":
    for i in xrange(2):
        print i
        prob = my_problem(i)
        algo = pygmo.algorithm.bee_colony(gen=500)
        isl = pygmo.island(algo,prob,20)
        isl.evolve(1)
        isl.join()
        print isl.population.champion.f
        print isl.population.champion.x

You will see that every time "i" is passed to the problem correctly, but then internally to "my_problem" p1 is restored to 10.

The only (ugly) work around that I found so far, is to renew class definition and its defaults within the for-loop.

if __name__=="__main__":
    for i in xrange(2):
        class my_problem(pygmo.problem.base):
            def __init__(self, par1 = i):
                    self.__dim = 10
                    self.p1 = par1
                    print self.p1
                    super(my_problem,self).__init__(self.__dim)
                    self.set_bounds(-5.12,5.12)

            def _objfun_impl(self,x):
                f = 0
                for i in range(self.__dim):
                    f = f + (x[i]/(1+self.p1))*(x[i])
                return (f,)

        print i
        prob = my_problem(i)
        algo = pygmo.algorithm.bee_colony(gen=500)
        isl = pygmo.island(algo,prob,20)
        isl.evolve(1)
        isl.join()
        print isl.population.champion.f
        print isl.population.champion.x

Is it really not possibly to pass time-to-time parameters to my function?

jmllorens commented 7 years ago

I think you are doing right. If you check the value of p1 in the _objfun_impl, you will see that it has the value passed when the object was instantiated:prob = my_problem(i). I don't know by heart what is going on, but my guess is that the "old" value is the value related with the class definition not with the created object. Try this in the first example:

 def _objfun_impl(self,x):
        f = 0
        print "function: ", self.p1
        for i in range(self.__dim):
            f = f + (x[i]/self.p1)*(x[i])
        return (f,)
mdepitta commented 7 years ago

@jmllorens Thanks. Indeed it looks like that .evolve is using the original definition and bypasses the time-to-time parameters. I posted this issue also on gitter, and see what the others also have to say. It is somehow limiting if I need to redefine the class for every set of parameters.