Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
1 change: 1 addition & 0 deletions .tools/envs/testenv-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ dependencies:
- pyyaml # dev, tests
- jinja2 # dev, tests
- annotated-types # dev, tests
- iminuit # dev, tests
- pip: # dev, tests, docs
- DFO-LS>=1.5.3 # dev, tests
- Py-BOBYQA # dev, tests
Expand Down
1 change: 1 addition & 0 deletions .tools/envs/testenv-numpy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ dependencies:
- pyyaml # dev, tests
- jinja2 # dev, tests
- annotated-types # dev, tests
- iminuit # dev, tests
- pip: # dev, tests, docs
- DFO-LS>=1.5.3 # dev, tests
- Py-BOBYQA # dev, tests
Expand Down
1 change: 1 addition & 0 deletions .tools/envs/testenv-others.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ dependencies:
- pyyaml # dev, tests
- jinja2 # dev, tests
- annotated-types # dev, tests
- iminuit # dev, tests
- pip: # dev, tests, docs
- DFO-LS>=1.5.3 # dev, tests
- Py-BOBYQA # dev, tests
Expand Down
1 change: 1 addition & 0 deletions .tools/envs/testenv-pandas.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ dependencies:
- pyyaml # dev, tests
- jinja2 # dev, tests
- annotated-types # dev, tests
- iminuit # dev, tests
- pip: # dev, tests, docs
- DFO-LS>=1.5.3 # dev, tests
- Py-BOBYQA # dev, tests
Expand Down
1 change: 1 addition & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ dependencies:
- jinja2 # dev, tests
- furo # dev, docs
- annotated-types # dev, tests
- iminuit # dev, tests
- pip: # dev, tests, docs
- DFO-LS>=1.5.3 # dev, tests
- Py-BOBYQA # dev, tests
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ dependencies = [
"sqlalchemy>=1.3",
"annotated-types",
"typing-extensions",
"iminuit",
]
dynamic = ["version"]
keywords = [
Expand Down
17 changes: 17 additions & 0 deletions src/optimagic/algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from optimagic.optimization.algorithm import Algorithm
from optimagic.optimizers.bhhh import BHHH
from optimagic.optimizers.fides import Fides
from optimagic.optimizers.iminuit_migrad import IminuitMigrad
from optimagic.optimizers.ipopt import Ipopt
from optimagic.optimizers.nag_optimizers import NagDFOLS, NagPyBOBYQA
from optimagic.optimizers.neldermead import NelderMeadParallel
Expand Down Expand Up @@ -286,6 +287,7 @@ def Scalar(self) -> BoundedGradientBasedLocalNonlinearConstrainedScalarAlgorithm
@dataclass(frozen=True)
class BoundedGradientBasedLocalScalarAlgorithms(AlgoSelection):
fides: Type[Fides] = Fides
iminuit_migrad: Type[IminuitMigrad] = IminuitMigrad
ipopt: Type[Ipopt] = Ipopt
nlopt_ccsaq: Type[NloptCCSAQ] = NloptCCSAQ
nlopt_lbfgsb: Type[NloptLBFGSB] = NloptLBFGSB
Expand Down Expand Up @@ -840,6 +842,7 @@ def NonlinearConstrained(
@dataclass(frozen=True)
class BoundedGradientBasedLocalAlgorithms(AlgoSelection):
fides: Type[Fides] = Fides
iminuit_migrad: Type[IminuitMigrad] = IminuitMigrad
ipopt: Type[Ipopt] = Ipopt
nlopt_ccsaq: Type[NloptCCSAQ] = NloptCCSAQ
nlopt_lbfgsb: Type[NloptLBFGSB] = NloptLBFGSB
Expand Down Expand Up @@ -889,6 +892,7 @@ def Scalar(self) -> GradientBasedLocalNonlinearConstrainedScalarAlgorithms:
@dataclass(frozen=True)
class GradientBasedLocalScalarAlgorithms(AlgoSelection):
fides: Type[Fides] = Fides
iminuit_migrad: Type[IminuitMigrad] = IminuitMigrad
ipopt: Type[Ipopt] = Ipopt
nlopt_ccsaq: Type[NloptCCSAQ] = NloptCCSAQ
nlopt_lbfgsb: Type[NloptLBFGSB] = NloptLBFGSB
Expand Down Expand Up @@ -956,6 +960,7 @@ def Scalar(self) -> BoundedGradientBasedNonlinearConstrainedScalarAlgorithms:
@dataclass(frozen=True)
class BoundedGradientBasedScalarAlgorithms(AlgoSelection):
fides: Type[Fides] = Fides
iminuit_migrad: Type[IminuitMigrad] = IminuitMigrad
ipopt: Type[Ipopt] = Ipopt
nlopt_ccsaq: Type[NloptCCSAQ] = NloptCCSAQ
nlopt_lbfgsb: Type[NloptLBFGSB] = NloptLBFGSB
Expand Down Expand Up @@ -1674,6 +1679,7 @@ def Scalar(self) -> BoundedLocalNonlinearConstrainedScalarAlgorithms:
@dataclass(frozen=True)
class BoundedLocalScalarAlgorithms(AlgoSelection):
fides: Type[Fides] = Fides
iminuit_migrad: Type[IminuitMigrad] = IminuitMigrad
ipopt: Type[Ipopt] = Ipopt
nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA
nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA
Expand Down Expand Up @@ -1943,6 +1949,7 @@ def Scalar(self) -> GlobalGradientBasedScalarAlgorithms:
class GradientBasedLocalAlgorithms(AlgoSelection):
bhhh: Type[BHHH] = BHHH
fides: Type[Fides] = Fides
iminuit_migrad: Type[IminuitMigrad] = IminuitMigrad
ipopt: Type[Ipopt] = Ipopt
nlopt_ccsaq: Type[NloptCCSAQ] = NloptCCSAQ
nlopt_lbfgsb: Type[NloptLBFGSB] = NloptLBFGSB
Expand Down Expand Up @@ -1985,6 +1992,7 @@ def Scalar(self) -> GradientBasedLocalScalarAlgorithms:
@dataclass(frozen=True)
class BoundedGradientBasedAlgorithms(AlgoSelection):
fides: Type[Fides] = Fides
iminuit_migrad: Type[IminuitMigrad] = IminuitMigrad
ipopt: Type[Ipopt] = Ipopt
nlopt_ccsaq: Type[NloptCCSAQ] = NloptCCSAQ
nlopt_lbfgsb: Type[NloptLBFGSB] = NloptLBFGSB
Expand Down Expand Up @@ -2054,6 +2062,7 @@ def Scalar(self) -> GradientBasedNonlinearConstrainedScalarAlgorithms:
@dataclass(frozen=True)
class GradientBasedScalarAlgorithms(AlgoSelection):
fides: Type[Fides] = Fides
iminuit_migrad: Type[IminuitMigrad] = IminuitMigrad
ipopt: Type[Ipopt] = Ipopt
nlopt_ccsaq: Type[NloptCCSAQ] = NloptCCSAQ
nlopt_lbfgsb: Type[NloptLBFGSB] = NloptLBFGSB
Expand Down Expand Up @@ -2577,6 +2586,7 @@ def Scalar(self) -> GlobalParallelScalarAlgorithms:
@dataclass(frozen=True)
class BoundedLocalAlgorithms(AlgoSelection):
fides: Type[Fides] = Fides
iminuit_migrad: Type[IminuitMigrad] = IminuitMigrad
ipopt: Type[Ipopt] = Ipopt
nag_dfols: Type[NagDFOLS] = NagDFOLS
nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA
Expand Down Expand Up @@ -2659,6 +2669,7 @@ def Scalar(self) -> LocalNonlinearConstrainedScalarAlgorithms:
@dataclass(frozen=True)
class LocalScalarAlgorithms(AlgoSelection):
fides: Type[Fides] = Fides
iminuit_migrad: Type[IminuitMigrad] = IminuitMigrad
ipopt: Type[Ipopt] = Ipopt
nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA
neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel
Expand Down Expand Up @@ -2809,6 +2820,7 @@ def Scalar(self) -> BoundedNonlinearConstrainedScalarAlgorithms:
@dataclass(frozen=True)
class BoundedScalarAlgorithms(AlgoSelection):
fides: Type[Fides] = Fides
iminuit_migrad: Type[IminuitMigrad] = IminuitMigrad
ipopt: Type[Ipopt] = Ipopt
nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA
nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA
Expand Down Expand Up @@ -3063,6 +3075,7 @@ def Local(self) -> LeastSquaresLocalParallelAlgorithms:
class GradientBasedAlgorithms(AlgoSelection):
bhhh: Type[BHHH] = BHHH
fides: Type[Fides] = Fides
iminuit_migrad: Type[IminuitMigrad] = IminuitMigrad
ipopt: Type[Ipopt] = Ipopt
nlopt_ccsaq: Type[NloptCCSAQ] = NloptCCSAQ
nlopt_lbfgsb: Type[NloptLBFGSB] = NloptLBFGSB
Expand Down Expand Up @@ -3246,6 +3259,7 @@ def Scalar(self) -> GlobalScalarAlgorithms:
class LocalAlgorithms(AlgoSelection):
bhhh: Type[BHHH] = BHHH
fides: Type[Fides] = Fides
iminuit_migrad: Type[IminuitMigrad] = IminuitMigrad
ipopt: Type[Ipopt] = Ipopt
nag_dfols: Type[NagDFOLS] = NagDFOLS
nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA
Expand Down Expand Up @@ -3316,6 +3330,7 @@ def Scalar(self) -> LocalScalarAlgorithms:
@dataclass(frozen=True)
class BoundedAlgorithms(AlgoSelection):
fides: Type[Fides] = Fides
iminuit_migrad: Type[IminuitMigrad] = IminuitMigrad
ipopt: Type[Ipopt] = Ipopt
nag_dfols: Type[NagDFOLS] = NagDFOLS
nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA
Expand Down Expand Up @@ -3451,6 +3466,7 @@ def Scalar(self) -> NonlinearConstrainedScalarAlgorithms:
@dataclass(frozen=True)
class ScalarAlgorithms(AlgoSelection):
fides: Type[Fides] = Fides
iminuit_migrad: Type[IminuitMigrad] = IminuitMigrad
ipopt: Type[Ipopt] = Ipopt
nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA
neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel
Expand Down Expand Up @@ -3625,6 +3641,7 @@ def Scalar(self) -> ParallelScalarAlgorithms:
class Algorithms(AlgoSelection):
bhhh: Type[BHHH] = BHHH
fides: Type[Fides] = Fides
iminuit_migrad: Type[IminuitMigrad] = IminuitMigrad
ipopt: Type[Ipopt] = Ipopt
nag_dfols: Type[NagDFOLS] = NagDFOLS
nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA
Expand Down
102 changes: 102 additions & 0 deletions src/optimagic/optimizers/iminuit_migrad.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
from dataclasses import dataclass
from typing import Callable, Optional

import numpy as np
from iminuit import Minuit # type: ignore
from numpy.typing import NDArray

from optimagic import mark
from optimagic.optimization.algo_options import (
STOPPING_MAXFUN,
)
from optimagic.optimization.algorithm import Algorithm, InternalOptimizeResult
from optimagic.optimization.internal_optimization_problem import (
InternalOptimizationProblem,
)
from optimagic.typing import AggregationLevel


@mark.minimizer(
name="iminuit_migrad",
solver_type=AggregationLevel.SCALAR,
is_available=True,
Comment thread
spline2hg marked this conversation as resolved.
Outdated
is_global=False,
needs_jac=True,
needs_hess=False,
supports_parallelism=False,
supports_bounds=True,
supports_linear_constraints=False,
supports_nonlinear_constraints=False,
disable_history=False,
)
@dataclass(frozen=True)
class IminuitMigrad(Algorithm):
stopping_maxfun: int = STOPPING_MAXFUN

def _solve_internal_problem(
self, problem: InternalOptimizationProblem, params: NDArray[np.float64]
) -> InternalOptimizeResult:
def wrapped_objective(x: NDArray[np.float64]) -> float:
return float(problem.fun(x))

wrapped_gradient = None
jac_func = None
if problem.jac is not None:
Comment thread
spline2hg marked this conversation as resolved.
Outdated

def wrapped_gradient(x: NDArray[np.float64]) -> NDArray[np.float64]:
return problem.jac(x)

jac_func = problem.jac
elif problem.fun_and_jac is not None:

def wrapped_gradient(x: NDArray[np.float64]) -> NDArray[np.float64]:
_, jac = problem.fun_and_jac(x)
return jac
Comment thread
spline2hg marked this conversation as resolved.
Outdated

jac_func = lambda x: problem.fun_and_jac(x)[1]

m = Minuit(wrapped_objective, params, grad=wrapped_gradient)
Comment thread
spline2hg marked this conversation as resolved.
Outdated

if problem.bounds:
lower_bounds = problem.bounds.lower
upper_bounds = problem.bounds.upper

if lower_bounds is not None and upper_bounds is not None:
for i, (lower, upper) in enumerate(
zip(lower_bounds, upper_bounds, strict=False)
Comment thread
spline2hg marked this conversation as resolved.
Outdated
):
if lower is not None or upper is not None:
m.limits[i] = (lower, upper)
Comment thread
spline2hg marked this conversation as resolved.
Outdated

m.migrad(ncall=self.stopping_maxfun)

res = process_minuit_result(m, jac_func)
return res


def process_minuit_result(
Comment thread
spline2hg marked this conversation as resolved.
Outdated
minuit_result: Minuit,
jac_fun: Optional[Callable[[NDArray[np.float64]], NDArray[np.float64]]] = None,
) -> InternalOptimizeResult:
jac = None
if jac_fun is not None:
jac = jac_fun(np.array(minuit_result.values))
Comment thread
spline2hg marked this conversation as resolved.
Outdated

res = InternalOptimizeResult(
x=np.array(minuit_result.values),
fun=minuit_result.fval,
success=minuit_result.valid,
message=repr(minuit_result.fmin),
n_fun_evals=minuit_result.nfcn,
n_jac_evals=minuit_result.ngrad,
n_hess_evals=None,
n_iterations=None,
Comment thread
spline2hg marked this conversation as resolved.
Outdated
status=None,
jac=jac,
hess=np.array(minuit_result.hesse()),
hess_inv=np.array(minuit_result.covariance),
max_constraint_violation=None,
info={"minos": minuit_result.minos()},
Comment thread
spline2hg marked this conversation as resolved.
Outdated
history=None,
)
return res