pints icon indicating copy to clipboard operation
pints copied to clipboard

Error from empty set_population_size() call in PopulationBasedOptimiser

Open mjowen opened this issue 1 year ago • 1 comments

Bug

Refusing to set a population size (using the default of population_size=None) leads to an error when the optimisation is run but the docstring for set_population_size suggests this is valid and the value generated by suggested_population_size should be used in this case.

I'm guessing this is just missing functionality from set_population_size, but I did see that the docstring for population_size mentions the possibility of self.population_size=None prior to beginning an optimisation, but I couldn't see any way for opt.run() to set this to default if that was the case

MRE

import pints
import pints.toy

model = pints.toy.ParabolicError()
opt = pints.OptimisationController(model, [1, 1], method=pints.CMAES)
opt.optimiser().set_population_size()
opt.run()

Relevant parts of pints

    def __init__(self, x0, sigma0=None, boundaries=None):
        super(PopulationBasedOptimiser, self).__init__(x0, sigma0, boundaries)

        # Set initial population size using heuristic
        self._population_size = self._suggested_population_size()

    def population_size(self):
        """
        Returns this optimiser's population size.

        If no explicit population size has been set, ``None`` may be returned.
        Once running, the correct value will always be returned.
        """
        return self._population_size

    def set_population_size(self, population_size=None):
        """
        Sets a population size to use in this optimisation.

        If `population_size` is set to ``None``, the population size will be
        set using the heuristic :meth:`suggested_population_size()`.
        """
        if self.running():
            raise Exception('Cannot change population size during run.')

        # Check population size or set using heuristic
        if population_size is not None:
            population_size = int(population_size)
            if population_size < 1:
                raise ValueError('Population size must be at least 1.')

        # Store
        self._population_size = population_size

    def suggested_population_size(self, round_up_to_multiple_of=None):
        """
        Returns a suggested population size for this method, based on the
        dimension of the search space (e.g. the parameter space).

        If the optional argument ``round_up_to_multiple_of`` is set to an
        integer greater than 1, the method will round up the estimate to a
        multiple of that number. This can be useful to obtain a population size
        based on e.g. the number of worker processes used to perform objective
        function evaluations.
        """
        population_size = self._suggested_population_size()

        if round_up_to_multiple_of is not None:
            n = int(round_up_to_multiple_of)
            if n > 1:
                population_size = n * (((population_size - 1) // n) + 1)

        return population_size

mjowen avatar Nov 14 '24 14:11 mjowen

Thanks @mjowen ! Will look into this

MichaelClerx avatar Dec 18 '24 16:12 MichaelClerx