Skip to content

Step 1: minimize with labeled parameters #1

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

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
35 changes: 34 additions & 1 deletion examples/example.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,44 @@
"source": [
"# Showcase how optimini is used"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1",
"metadata": {},
"outputs": [],
"source": [
"import optimini as om\n",
"\n",
"\n",
"def my_fun(params):\n",
" return params[\"a\"] ** 2 + params[\"b\"] ** 2\n",
"\n",
"\n",
"params = {\"a\": 1, \"b\": 2}\n",
"res = om.minimize(my_fun, params, method=\"L-BFGS-B\")\n",
"res.x"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "optimini",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python"
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.11"
}
},
"nbformat": 4,
Expand Down
3 changes: 3 additions & 0 deletions src/optimini/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from optimini.minimize import minimize

__all__ = ["minimize"]
18 changes: 18 additions & 0 deletions src/optimini/converter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import numpy as np


class Converter:
"""Class to convert between parameter dictionaries and numpy arrays"""

def __init__(self, params):
self.original = params

def flatten(self, params):
if isinstance(params, dict):
params = np.array(list(params.values()))
return params

def unflatten(self, x):
if isinstance(self.original, dict):
x = dict(zip(self.original.keys(), x.tolist(), strict=False))
return x
10 changes: 10 additions & 0 deletions src/optimini/internal_problem.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class InternalProblem:
"""Wraps a user provided function to add functionality"""

def __init__(self, fun, converter):
self._user_fun = fun
self._converter = converter

def fun(self, x):
params = self._converter.unflatten(x)
return self._user_fun(params)
23 changes: 23 additions & 0 deletions src/optimini/minimize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from copy import deepcopy

from scipy.optimize import minimize as scipy_minimize

from optimini.converter import Converter
from optimini.internal_problem import InternalProblem


def minimize(fun, params, method, options=None):
"""Minimize a function using a given method"""
options = {} if options is None else options
converter = Converter(params)
problem = InternalProblem(fun, converter)
x0 = converter.flatten(params)
raw_res = scipy_minimize(
fun=problem.fun,
x0=x0,
method=method,
options=options,
)
res = deepcopy(raw_res)
res.x = converter.unflatten(res.x)
return res
26 changes: 26 additions & 0 deletions tests/test_optimini.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import numpy as np

from optimini.minimize import minimize


def dict_fun(params):
return params["a"] ** 2 + params["b"] ** 2


def array_fun(params):
return params @ params


def test_simple_minimize_with_dict_params():
params = {"a": 1, "b": 2}
res = minimize(dict_fun, params, method="L-BFGS-B")
assert isinstance(res.x, dict)
assert np.allclose(res.x["a"], 0)
assert np.allclose(res.x["b"], 0)


def test_simple_minimize_with_array_params():
params = np.array([1, 2])
res = minimize(array_fun, params, method="L-BFGS-B")
assert isinstance(res.x, np.ndarray)
assert np.allclose(res.x, np.array([0, 0]))