Skip to content
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

Implement the new interface for objective functions and derivatives #512

Merged
merged 32 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
ab226a0
Preparations.
janosg Aug 1, 2024
07ec9f1
Add unit tests.
janosg Aug 1, 2024
1c06dcf
Refactoring.
janosg Aug 2, 2024
375ed28
Fix merge conflicts.
janosg Aug 2, 2024
eada6b8
Add internal_value method to subclasses of FunctionValue.
janosg Aug 2, 2024
0801733
Renaming.
janosg Aug 3, 2024
3c33c22
Combine the different enforce decorators into one.
janosg Aug 3, 2024
69303bd
Do the core change.
janosg Aug 6, 2024
6205334
Fix merge conflicts.
janosg Aug 6, 2024
97269e7
Remove dead code.
janosg Aug 7, 2024
6bdf854
Combine ProblemType and SolverType to AggregationLevel.
janosg Aug 7, 2024
71bb339
Cleanup.
janosg Aug 7, 2024
3836931
Cleanup.
janosg Aug 7, 2024
114eafd
Fix merge conflicts.
janosg Aug 7, 2024
a07375f
Clean up criterion_functions.py.
janosg Aug 7, 2024
7835c66
Fix deprecation warnings stemming from derivatives (#516)
timmens Aug 7, 2024
c6f1bde
Fix future warnings.
janosg Aug 7, 2024
c6205b0
Add full pytree handling to criterion_functions.py.
janosg Aug 7, 2024
faae4fa
Fix warnings in estimate_ml.
janosg Aug 7, 2024
7b5b514
Fix remaining warnings.
janosg Aug 7, 2024
6020863
Implement new interface for derivatives.
janosg Aug 8, 2024
09a173a
Add tests for new function formats.
janosg Aug 8, 2024
e1ea722
Add tests for future warnings.
janosg Aug 8, 2024
a352527
Remove problem_type from OptimizationProblem.
janosg Aug 8, 2024
ad94056
Add how-to guide for objective functions.
janosg Aug 8, 2024
19ce4a8
Fix.
janosg Aug 8, 2024
2cd1aa7
Write how-to guide for derivatives.
janosg Aug 8, 2024
ae2b95d
Write how-to guide for derivatives.
janosg Aug 8, 2024
cf77e8d
Incorporate comments from review.
janosg Aug 9, 2024
4a2bbb8
Incorporate comments from review.
janosg Aug 9, 2024
6f9061b
Incorporate comments from review.
janosg Aug 9, 2024
cff766b
Fix warning.
janosg Aug 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions docs/source/how_to/how_to_algorithm_selection.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,9 @@
"metadata": {},
"outputs": [],
"source": [
"@om.mark.least_squares\n",
"def sphere(params):\n",
" out = {\n",
" \"value\": params @ params,\n",
" \"root_contributions\": params,\n",
" }\n",
" return out\n",
" return params\n",
"\n",
"\n",
"def sphere_gradient(params):\n",
Expand Down
226 changes: 226 additions & 0 deletions docs/source/how_to/how_to_criterion_function.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
{
janosg marked this conversation as resolved.
Show resolved Hide resolved
janosg marked this conversation as resolved.
Show resolved Hide resolved
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# How to write objective functions\n",
"\n",
"optimagic is very flexible when it comes to the objective function and its derivatives. \n",
"In this how-to guide we start with simple examples, that would also work with \n",
"scipy.optimize before we show advanced options and their advantages. \n",
"\n",
"## The simplest case\n",
"\n",
"In the simplest case, `fun` maps a numpy array into a scalar objective value. The name\n",
"of first argument of `fun` is arbitrary. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import optimagic as om\n",
"\n",
"\n",
"def sphere(x):\n",
" return x @ x\n",
"\n",
"\n",
"res = om.minimize(\n",
" fun=sphere,\n",
" params=np.arange(3),\n",
" algorithm=\"scipy_lbfgsb\",\n",
")\n",
"res.params.round(6)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## More flexible `params`\n",
"\n",
"In all but the most simple problems, a flat numpy array is not ideal to keep track of \n",
"all the different parameters one wants to optimize over. Therefore, optimagic accepts \n",
"objective functions that work with other parameter formats. Below we show a simple \n",
"example. More examples can be found [here](how_to_start_parameters.md).\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def dict_fun(x):\n",
" return x[\"a\"] ** 2 + x[\"b\"] ** 4\n",
"\n",
"\n",
"res = om.minimize(\n",
" fun=dict_fun,\n",
" params={\"a\": 1, \"b\": 2},\n",
" algorithm=\"scipy_lbfgsb\",\n",
")\n",
"\n",
"res.params"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The important thing is that the `params` provided to `minimize` need to have the format \n",
"that is expected by the objective function.\n",
"\n",
"## Functions with additional arguments\n",
"\n",
"In many applications, the objective function takes more than `params` as argument. \n",
"This can be achieved via `fun_kwargs`. Take the following simplified example:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def shifted_sphere(x, offset):\n",
" return (x - offset) @ (x - offset)\n",
"\n",
"\n",
"res = om.minimize(\n",
" fun=shifted_sphere,\n",
" params=np.arange(3),\n",
" algorithm=\"scipy_lbfgsb\",\n",
" fun_kwargs={\"offset\": np.ones(3)},\n",
")\n",
"res.params"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`fun_kwargs` is a dictionary with keyword arguments for `fun`. There is no constraint\n",
"on the number or names of those arguments."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Least-Squares problems\n",
"\n",
"Many estimation problems have a least-squares structure. If so, specialized optimizers that exploit this structure can be much faster than standard optimizers. The `sphere` function from above is the simplest possible least-squarse problem you could imagine: the least-squares residuals are just the params. \n",
"\n",
"To use least-squares optimizers in optimagic, you need to mark your function with \n",
"a decorator and return the least-squares residuals instead of the aggregated function value. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"@om.mark.least_squares\n",
"def ls_sphere(params):\n",
" return params\n",
"\n",
"\n",
"res = om.minimize(\n",
" fun=ls_sphere,\n",
" params=np.arange(3),\n",
" algorithm=\"pounders\",\n",
")\n",
"res.params.round(5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Any least-squares optimization problem is also a standard optimization problem. You \n",
"can therefore optimize least-squares functions with scalar optimizers as well:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"res = om.minimize(\n",
" fun=ls_sphere,\n",
" params=np.arange(3),\n",
" algorithm=\"scipy_lbfgsb\",\n",
")\n",
"res.params.round(5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Returning additional information\n",
"\n",
"You can return additional information such as intermediate results, debugging information, etc. in your objective function. This information will be stored in a database if you use [logging](how_to_logging.ipynb).\n",
"\n",
"To do so, you need to return a `FunctionValue` object."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def sphere_with_info(x):\n",
" return om.FunctionValue(value=x @ x, info={\"avg\": x.mean()})\n",
"\n",
"\n",
"res = om.minimize(\n",
" fun=sphere_with_info,\n",
" params=np.arange(3),\n",
" algorithm=\"scipy_lbfgsb\",\n",
")\n",
"\n",
"res.params.round(6)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `info` can be an arbitrary dictionary. In the oversimplified example we returned the \n",
"mean of the parameters, which could have been recovered from the params history that \n",
"is collected anyways but in real applications this feature can be helpful. "
]
}
],
"metadata": {
"kernelspec": {
"display_name": "optimagic",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.14"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
6 changes: 0 additions & 6 deletions docs/source/how_to/how_to_criterion_function.md

This file was deleted.

Loading