-
Notifications
You must be signed in to change notification settings - Fork 48
Unified Interface: Absolute Tolerance #1660
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from 4 commits
816df12
cef62b6
649cb24
e5ab895
1940557
d7e86fc
684077a
cbae8ff
4c7ad9c
c2f4d73
be9fd7a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -413,6 +413,58 @@ def set_maxeval(self, evaluations: int) -> None: | |
| f"Check supports_maxeval() before calling set_maxeval()." | ||
| ) | ||
|
|
||
| def supports_tol(self) -> bool: | ||
| """ | ||
| Check whether optimizer supports absolute tolerance. | ||
|
|
||
| Returns | ||
| ------- | ||
| True if optimizer supports setting an absolute tolerance, | ||
| False otherwise. | ||
| """ | ||
| return True | ||
|
|
||
| def set_tol(self, tol: float) -> None: | ||
| """ | ||
| Set the absolute tolerance for optimization. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| tol | ||
| Absolute tolerance for termination. | ||
|
|
||
| Raises | ||
| ------ | ||
| NotImplementedError | ||
| If the optimizer does not support absolute tolerance. | ||
| """ | ||
| raise NotImplementedError( | ||
| f"{self.__class__.__name__} does not support absolute tolerance. " | ||
| f"Check supports_tol() before calling set_tol()." | ||
| ) | ||
|
|
||
| def _set_option_tol(self, tol: float, option_key: str) -> None: | ||
| """ | ||
| Set tolerance in options dict with validation. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| tol | ||
| Absolute tolerance value (must be positive). | ||
| option_key | ||
| The key to use in the options dictionary. | ||
|
|
||
| Raises | ||
| ------ | ||
| ValueError | ||
| If tolerance is not positive. | ||
| """ | ||
| if tol < 0: | ||
| raise ValueError(f"Tolerance must be positive, got {tol}") | ||
| if self.options is None: | ||
| self.options = {} | ||
| self.options[option_key] = tol | ||
|
|
||
|
|
||
| class ScipyOptimizer(Optimizer): | ||
| """ | ||
|
|
@@ -670,6 +722,24 @@ def set_maxiter(self, iterations: int) -> None: | |
| else: | ||
| self.options["maxiter"] = iterations | ||
|
|
||
| def set_tol(self, tol: float) -> None: | ||
| """ | ||
| Set the absolute tolerance for optimization. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| tol | ||
| Absolute tolerance for termination. | ||
|
|
||
| Raises | ||
| ------ | ||
| ValueError | ||
| If tolerance is not positive. | ||
| """ | ||
| if tol <= 0: | ||
| raise ValueError(f"Tolerance must be positive, got {tol}") | ||
| self.tol = tol | ||
|
|
||
|
|
||
| class IpoptOptimizer(Optimizer): | ||
| """Use Ipopt (https://pypi.org/project/cyipopt/) for optimization.""" | ||
|
|
@@ -789,6 +859,17 @@ def set_maxiter(self, iterations: int) -> None: | |
| self.options = {} | ||
| self.options["max_iter"] = iterations | ||
|
|
||
| def set_tol(self, tol: float) -> None: | ||
| """ | ||
| Set the absolute tolerance for optimization. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| tol | ||
| Absolute tolerance for termination. | ||
| """ | ||
| self._set_option_tol(tol, "tol") | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From what I remember, ipopt has quite complex termination criteria. While various tolerances are supported, I think just hitting this single value is insufficient for termination, so it might be a bit confusing. Not completely sure whether it should be added here or not.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. True, it says so in the IPOPT documentation with a quite lengthy passage. I would in general be fine with removing it, but i am not sure how to handle the |
||
|
|
||
|
|
||
| class DlibOptimizer(Optimizer): | ||
| """Use the Dlib toolbox for optimization.""" | ||
|
|
@@ -912,6 +993,10 @@ def set_maxiter(self, iterations: int) -> None: | |
| self.options = {} | ||
| self.options["maxiter"] = iterations | ||
|
|
||
| def supports_tol(self) -> bool: | ||
| """Check whether optimizer supports absolute tolerance.""" | ||
| return False | ||
|
|
||
|
|
||
| class PyswarmOptimizer(Optimizer): | ||
| """Global optimization using pyswarm.""" | ||
|
|
@@ -987,6 +1072,17 @@ def set_maxiter(self, iterations: int) -> None: | |
| self.options = {} | ||
| self.options["maxiter"] = iterations | ||
|
|
||
| def set_tol(self, tol: float) -> None: | ||
| """ | ||
| Set the absolute tolerance for optimization. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| tol | ||
| Absolute tolerance for termination. | ||
| """ | ||
| self._set_option_tol(tol, "minfunc") | ||
|
|
||
|
|
||
| class CmaOptimizer(Optimizer): | ||
| """ | ||
|
|
@@ -1100,6 +1196,17 @@ def set_maxeval(self, evaluations: int) -> None: | |
| self.options = {} | ||
| self.options["maxfevals"] = evaluations | ||
|
|
||
| def set_tol(self, tol: float) -> None: | ||
| """ | ||
| Set the absolute tolerance for optimization. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| tol | ||
| Absolute tolerance for termination. | ||
| """ | ||
| self._set_option_tol(tol, "tolfun") | ||
|
|
||
|
|
||
| class CmaesOptimizer(CmaOptimizer): | ||
| """Deprecated, use CmaOptimizer instead.""" | ||
|
|
@@ -1201,6 +1308,17 @@ def set_maxiter(self, iterations: int) -> None: | |
| self.options = {} | ||
| self.options["maxiter"] = iterations | ||
|
|
||
| def set_tol(self, tol: float) -> None: | ||
| """ | ||
| Set the absolute tolerance for optimization. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| tol | ||
| Absolute tolerance for termination. | ||
| """ | ||
| self._set_option_tol(tol, "atol") | ||
|
|
||
|
|
||
| class PyswarmsOptimizer(Optimizer): | ||
| """ | ||
|
|
@@ -1342,6 +1460,10 @@ def set_maxiter(self, iterations: int) -> None: | |
| self.options = {} | ||
| self.options["maxiter"] = iterations | ||
|
|
||
| def supports_tol(self) -> bool: | ||
| """Check whether optimizer supports absolute tolerance.""" | ||
| return False | ||
|
|
||
|
|
||
| class NLoptOptimizer(Optimizer): | ||
| """ | ||
|
|
@@ -1614,6 +1736,17 @@ def set_maxeval(self, evaluations: int) -> None: | |
| """ | ||
| self.options["maxeval"] = evaluations | ||
|
|
||
| def set_tol(self, tol: float) -> None: | ||
| """ | ||
| Set the absolute tolerance for optimization. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| tol | ||
| Absolute tolerance for termination. | ||
| """ | ||
| self._set_option_tol(tol, "ftol_abs") | ||
|
|
||
|
|
||
| class FidesOptimizer(Optimizer): | ||
| """ | ||
|
|
@@ -1838,3 +1971,19 @@ def set_maxiter(self, iterations: int) -> None: | |
| self.options[FidesOptions.MAXITER] = iterations | ||
| except ImportError: | ||
| raise OptimizerImportError("fides") from None | ||
|
|
||
| def set_tol(self, tol: float) -> None: | ||
| """ | ||
| Set the absolute tolerance for optimization. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| tol | ||
| Absolute tolerance for termination. | ||
| """ | ||
| try: | ||
| from fides.constants import Options as FidesOptions | ||
|
|
||
| self._set_option_tol(tol, FidesOptions.FATOL) | ||
| except ImportError: | ||
| raise OptimizerImportError("fides") from None | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
class Optimizerdoes not have anoptionsattribute, we should not try accessing it here. I'd leave validation to the optimizer and just set the options directly in each optimizer without this extra method.