Expected an unbounded problem, but this problem has lower and/or upper bounds.
I have a bounded problem, I tried both PGPE and CMAES but I get the error:
Expected an unbounded problem, but this problem has lower and/or upper bounds.
Is there any solver for bounded problems?
Hello turian,
Thank you for your question, and for trying out EvoTorch!
These algorithms support bounded problems:
- GeneticAlgorithm (see: https://docs.evotorch.ai/v0.5.1/reference/evotorch/algorithms/ga/#evotorch.algorithms.ga.GeneticAlgorithm)
- Cosyne (see: https://docs.evotorch.ai/v0.5.1/reference/evotorch/algorithms/ga/#evotorch.algorithms.ga.Cosyne)
- PyCMAES (which is an interface for the CMAEvolutionStrategy solver provided by the
cmalibrary; see: https://docs.evotorch.ai/v0.5.1/reference/evotorch/algorithms/pycmaes/#evotorch.algorithms.pycmaes.PyCMAES)
Distribution-based search algorithm implementations of EvoTorch such as PGPE and CMAES do not support strictly bounded problems. Still, you could define initial_bounds, and then augment your fitness function by adding penalty terms to discourage the exploration of the infeasible regions.
I think such an augmented problem definition could look like this (I hope it works and/or helps, feel free to let me know):
import torch
from evotorch import Problem, SolutionBatch
class MyBoundedProblem(Problem):
...
def _evaluate_batch(self, batch: SolutionBatch):
# Take the decision values from the solution batch
values = batch.values
# identify where the lower and upper bounds are violated within the batch
lb_violated = values < self.lower_bounds
ub_violated = values > self.upper_bounds
# for each solution within the batch, compute the total amount of violation
violation_amounts = (
torch.where(lb_violated, self.lower_bounds - values, 0.0)
+ torch.where(ub_violated, values - self.upper_bounds, 0.0)
).sum(dim=-1)
# get the clipped counterpart of the values, such that the boundaries are not
# violated anymore
clipped_values = torch.where(lb_violated, self.lower_bounds, values)
clipped_values = torch.where(ub_violated, self.upper_bounds, clipped_values)
# compute the fitnesses (or solution costs) using the clipped decision values
fitnesses = SomehowComputeTheFitnesses(clipped_values)
penalty_sign = 1.0 if self.objective_sense == "min" else -1.0
# the magnitude of the penalty is 100 times the violation squared
# (needs tuning according to the fitness scale of the problem at hand)
penalties = penalty_sign * 100.0 * (violation_amounts ** 2)
# Evaluations take into account fitnesses and the penalties
batch.set_evals(fitnesses + penalties)
EvoTorch also introduced helper functions for detecting the amount of violations for constraints, and for penalizing them (using exponential penalization or using log barriers), but they have not been included in a release yet: https://github.com/nnaisense/evotorch/blob/master/src/evotorch/tools/constraints.py. If you are okay with installing EvoTorch directly from its master branch on GitHub, you could also use these helper functions, if you prefer.
Feel free to let us know if you have further questions, or if something is not clear.