From 64cf934d3a947b3c1b044286aa5009eca2329aaa Mon Sep 17 00:00:00 2001 From: Janos Gabler Date: Wed, 17 Jul 2024 14:46:56 +0200 Subject: [PATCH] Add x0 as alias for params. --- src/optimagic/exceptions.py | 4 ++ src/optimagic/optimization/optimize.py | 27 +++++++++++- .../optimization/test_scipy_aliases.py | 43 +++++++++++++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 tests/optimagic/optimization/test_scipy_aliases.py diff --git a/src/optimagic/exceptions.py b/src/optimagic/exceptions.py index 559a14532..6d63a7de0 100644 --- a/src/optimagic/exceptions.py +++ b/src/optimagic/exceptions.py @@ -27,6 +27,10 @@ class MissingInputError(OptimagicError): """Exception for missing user provided input.""" +class AliasError(OptimagicError): + """Exception for aliasing errors.""" + + class InvalidKwargsError(OptimagicError): """Exception for invalid user provided keyword arguments.""" diff --git a/src/optimagic/optimization/optimize.py b/src/optimagic/optimization/optimize.py index 1bf25b03b..2ccde1bae 100644 --- a/src/optimagic/optimization/optimize.py +++ b/src/optimagic/optimization/optimize.py @@ -7,6 +7,7 @@ InvalidFunctionError, InvalidKwargsError, MissingInputError, + AliasError, ) from optimagic.logging.create_tables import ( make_optimization_iteration_table, @@ -63,6 +64,8 @@ def maximize( multistart_options=None, collect_history=True, skip_checks=False, + # scipy aliases + x0=None, # deprecated arguments criterion=None, criterion_kwargs=None, @@ -99,6 +102,8 @@ def maximize( multistart_options=multistart_options, collect_history=collect_history, skip_checks=skip_checks, + # scipy aliases + x0=x0, # deprecated arguments criterion=criterion, criterion_kwargs=criterion_kwargs, @@ -136,6 +141,8 @@ def minimize( multistart_options=None, collect_history=True, skip_checks=False, + # scipy aliases + x0=None, # deprecated arguments criterion=None, criterion_kwargs=None, @@ -173,6 +180,8 @@ def minimize( multistart_options=multistart_options, collect_history=collect_history, skip_checks=skip_checks, + # scipy aliases + x0=x0, # deprecated arguments criterion=criterion, criterion_kwargs=criterion_kwargs, @@ -211,6 +220,8 @@ def _optimize( multistart_options, collect_history, skip_checks, + # scipy aliases + x0, # deprecated arguments criterion, criterion_kwargs, @@ -239,7 +250,7 @@ def _optimize( ) raise MissingInputError(msg) - if params is None: + if params is None and x0 is None: msg = ( "Missing start parameters. Please provide start parameters as the second " "positional argument or as the keyword argument `params`." @@ -328,6 +339,20 @@ def _optimize( if fun_and_jac_kwargs is None: fun_and_jac_kwargs = criterion_and_derivative_kwargs + # ================================================================================== + # handle scipy aliases + # ================================================================================== + + if x0 is not None: + if params is not None: + msg = ( + "x0 is an alias for params (for better compatibility with scipy). " + "Do not use both x0 and params." + ) + raise AliasError(msg) + else: + params = x0 + # ================================================================================== # Set default values and check options # ================================================================================== diff --git a/tests/optimagic/optimization/test_scipy_aliases.py b/tests/optimagic/optimization/test_scipy_aliases.py new file mode 100644 index 000000000..ea035d117 --- /dev/null +++ b/tests/optimagic/optimization/test_scipy_aliases.py @@ -0,0 +1,43 @@ +import optimagic as om +import numpy as np +from numpy.testing import assert_array_almost_equal as aaae +from optimagic.exceptions import AliasError +import pytest + + +def test_x0_works_in_minimize(): + res = om.minimize( + fun=lambda x: x @ x, + x0=np.arange(3), + algorithm="scipy_lbfgsb", + ) + aaae(res.params, np.zeros(3)) + + +def test_x0_works_in_maximize(): + res = om.maximize( + fun=lambda x: -x @ x, + x0=np.arange(3), + algorithm="scipy_lbfgsb", + ) + aaae(res.params, np.zeros(3)) + + +def test_x0_and_params_do_not_work_together_in_minimize(): + with pytest.raises(AliasError, match="x0 is an alias"): + om.minimize( + fun=lambda x: x @ x, + x0=np.arange(3), + params=np.arange(3), + algorithm="scipy_lbfgsb", + ) + + +def test_x0_and_params_do_not_work_together_in_maximize(): + with pytest.raises(AliasError, match="x0 is an alias"): + om.maximize( + fun=lambda x: -x @ x, + x0=np.arange(3), + params=np.arange(3), + algorithm="scipy_lbfgsb", + )