esa / pygmo2

A Python platform to perform parallel computations of optimisation tasks (global and local) via the asynchronous generalized island model.
https://esa.github.io/pygmo2/
Mozilla Public License 2.0
422 stars 57 forks source link

[BUG] Meta-problem decorator for the fitness function does not work with algo.evolve(pop) #78

Closed means-to-meaning closed 2 years ago

means-to-meaning commented 3 years ago

Describe the bug Meta-problem decorator for the fitness function does not work with algo.evolve(pop)

To Reproduce Below code mostly taken from: https://esa.github.io/pygmo2/tutorials/udp_meta_decorator.html

import pygmo as pg

def f_log_decor(orig_fitness_function):
    def new_fitness_function(self, dv):
        if hasattr(self, "dv"):
            self.dv.append(dv)
        else:
            self.dv = [dv]
        return orig_fitness_function(self, dv)
    return new_fitness_function

rb = pg.rosenbrock()
drb = pg.problem(pg.decorator_problem(rb, fitness_decorator=f_log_decor))
algo = pg.algorithm(pg.cmaes(gen=20, sigma0=0.3))
pop = pg.population(drb, 10)
pop = algo.evolve(pop)

assert(hasattr(drb.extract(pg.decorator_problem), "dv"))

Expected behavior While the documentation for the decorator is nice and works as expected when calling the fitness function directly, the standard way to execute Pygmo is via algo.evolve(pop), which seems to render the decorator useless since the fitness function isn't triggered. This should probably not be labeled as a bug - but certainly unexpected behaviour, as we would hope the decorator to be called as part of the algo evolving. Alternatively, there is perhaps a way to call the fitness function directly to accomplish what algo.evolve() does, but I haven't seen a clear example in the docs.

Screenshots NA

Environment (please complete the following information):

Additional context

bluescarni commented 2 years ago

@means-to-meaning sorry for the late reply...

In your example, you are trying to extract the log from the original problem instance. However, pygmo normally operates with deep copy semantics.

In the specific snippet you posted, pop = pg.population(drb, 10) deep-copies drb into the pop object. Then, when you do pop = algo.evolve(pop), pop will be a deep copy of the evolved population.

In other words, you need to write

assert(hasattr(pop.problem.extract(pg.decorator_problem), "dv"))

rather than

assert(hasattr(drb.extract(pg.decorator_problem), "dv"))
bluescarni commented 2 years ago

Closing the report for now as this is the expected behaviour. Please re-open if needed.