Commit f97a0ab4 authored by Tjerk Vreeken's avatar Tjerk Vreeken

Improve goal function range vs. targets check

We now check that the target min/max are not equal to the function range
lower bound/upper bound respectively as well.

A target minimum equal to the lower bound of the function range does not
make any sense, as the corresponding epsilon is then free (and will
therefore always become zero). Effectively, the goal will behave as a
critical goal, and users should use those instead if such behavior is
desired.
parent 5f3e17df
......@@ -537,13 +537,15 @@ class GoalProgrammingMixin(OptimizationProblem, metaclass=ABCMeta):
# Check consistency between target and function range
if goal.has_target_min:
if goal.target_min < goal.function_range[0]:
if goal.target_min <= goal.function_range[0]:
raise Exception(
'Target minimum is smaller than the lower bound of the function range for goal {}'.format(goal))
'Target minimum should be greater than the lower bound of the function range for goal {}'.format(
goal))
if goal.has_target_max:
if goal.target_max > goal.function_range[1]:
if goal.target_max >= goal.function_range[1]:
raise Exception(
'Target maximum is greater than the upper bound of the function range for goal {}'.format(goal))
'Target maximum should be smaller than the upper bound of the function range for goal {}'.format(
goal))
if isinstance(epsilon, ca.MX):
if goal.has_target_bounds:
......
......@@ -607,3 +607,49 @@ class TestGoalProgrammingStateGoals(TestCase):
for x in self.problem.extract_results()["x"]:
self.assertAlmostGreaterThan(x, 0.0, value_tol)
self.assertAlmostLessThan(x, 1.1, value_tol)
class TestProblemInvalidGoals(TestProblem):
_goals = []
def goals(self):
return self._goals
class InvalidGoal(Goal):
def __init__(self, function_range, target_min=np.nan, target_max=np.nan):
self.function_range = function_range
self.target_min = target_min
self.target_max = target_max
def function(self, optimization_problem, ensemble_member):
return optimization_problem.state_at("x", 0.5, ensemble_member=ensemble_member)
priority = 1
class TestGoalProgrammingInvalidGoals(TestCase):
def setUp(self):
self.problem = TestProblemInvalidGoals()
def test_target_min_lt_function_range_lb(self):
self.problem._goals = [InvalidGoal((-2.0, 2.0), target_min=-3.0)]
with self.assertRaisesRegexp(Exception, "minimum should be greater than the lower"):
self.problem.optimize()
def test_target_min_eq_function_range_lb(self):
self.problem._goals = [InvalidGoal((-2.0, 2.0), target_min=-2.0)]
with self.assertRaisesRegexp(Exception, "minimum should be greater than the lower"):
self.problem.optimize()
def test_target_max_gt_function_range_ub(self):
self.problem._goals = [InvalidGoal((-2.0, 2.0), target_max=3.0)]
with self.assertRaisesRegexp(Exception, "maximum should be smaller than the upper"):
self.problem.optimize()
def test_target_max_eq_function_range_ub(self):
self.problem._goals = [InvalidGoal((-2.0, 2.0), target_max=2.0)]
with self.assertRaisesRegexp(Exception, "maximum should be smaller than the upper"):
self.problem.optimize()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment