A recent addition to scipy's differential_evolution implementation is to allow custom strategies, which should be a callable. Here is a simplistic example.
from scipy.optimize import differential_evolution
import numpy as np
def f(x):
return np.abs(x).sum()
bounds = ((-1, 1),)*3
class Strategy:
def __init__(self):
pass
def __call__(self, candidate:int, population:np.ndarray, rng=None) -> np.ndarray:
return population[candidate]
result = differential_evolution(
f,
bounds,
strategy=Strategy(),
)
The question is, how can you access the properties of the DifferentialEvolutionSolver which calls the strategy? These properties are rather important to any given strategy, and the inbuilt strategies have access to them - but I cannot see how to let a custom strategy access them.
A recent addition to scipy's differential_evolution implementation is to allow custom strategies, which should be a callable. Here is a simplistic example.
from scipy.optimize import differential_evolution
import numpy as np
def f(x):
return np.abs(x).sum()
bounds = ((-1, 1),)*3
class Strategy:
def __init__(self):
pass
def __call__(self, candidate:int, population:np.ndarray, rng=None) -> np.ndarray:
return population[candidate]
result = differential_evolution(
f,
bounds,
strategy=Strategy(),
)
The question is, how can you access the properties of the DifferentialEvolutionSolver which calls the strategy? These properties are rather important to any given strategy, and the inbuilt strategies have access to them - but I cannot see how to let a custom strategy access them.
Share Improve this question asked Mar 3 at 6:38 HmwatHmwat 1195 bronze badges 3 |1 Answer
Reset to default 2One shouldn't need to access scale
(the mutation
constant) because your custom strategy has total control over how it generates trials. If one uses a custom strategy then mutation
and recombination
variables are redundant.
In your Strategy
class you could create scale
/recombination
attributes that you can alter how you like. You know it's a new iteration when candidate
clocks over 0. If you want to alter them randomly then you have access to the same rng
that the solver uses. This doesn't seem crufty to me, it seems to be better than adding lots of keywords to the custom strategy.
I can see that wanting to use the population energies might be useful, but again I wouldn't necessarily want to provide them to the custom strategy (extra parameters) without further consideration (needs to be a good use case demonstrated). Note that the population and population energies are available at the end of each iteration via the callback
.
You can use the DifferentialEvolutionSolver
class directly, which provide all the flexibility you want, but it is a private class (use at own risk, the internals could change, things might be renamed, etc).
Making the solver class public has been considered, but that would be best done as part of a wider effort making solvers available through classes.
scipy.optimize._differentialevolution.DifferentialEvolutionSolver
, constructing the object yourself, and calling solve() on that object. – Nick ODell Commented Mar 3 at 13:57self
to access properties of theDifferentialEvolutionSolver
, they could be implemented without them. (e.g.self.population
could be replaced by the argumentpopulation
.samples
could be replaced by selecting indices at random without replacement. – Nick ODell Commented Mar 3 at 14:04self.scale
which I would like to access at the moment. There is a workaround in just using therng
externally to theDifferentialEvolutionSolver
but this isn't very elegant. If I were able to access more properties, I would like to design a more complicated strategy which would also requireself.population_energies
– Hmwat Commented Mar 3 at 23:15