Skip to content
Merged
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
14 changes: 13 additions & 1 deletion src/functionminimum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ FunctionMinimum init2(const MnUserTransformation& tr, py::sequence par,
py::tuple fmin_getstate(const FunctionMinimum&);
FunctionMinimum fmin_setstate(py::tuple);

bool hesse_failed_workaround(const FunctionMinimum& self) {
// Calling FunctionMinimum::HesseFailed is not reliable.
// It calls MinimumError::HesseFailed, but this is false if
// there were the failures MinimumError::MnReachedCallLimit
// or MinimumError::MnInvertFailed, which cannot be queried
// from FunctionMinimum.
//
// As a workaround, we return true if covariance exists, but
// is not accurate or made positive definite.
return self.HasCovariance() && !(self.HasPosDefCovar() || self.HasMadePosDefCovar());
}

void bind_functionminimum(py::module m) {
py::class_<FunctionMinimum>(m, "FunctionMinimum")

Expand All @@ -42,7 +54,7 @@ void bind_functionminimum(py::module m) {
.def_property_readonly("has_posdef_covar", &FunctionMinimum::HasPosDefCovar)
.def_property_readonly("has_made_posdef_covar",
&FunctionMinimum::HasMadePosDefCovar)
.def_property_readonly("hesse_failed", &FunctionMinimum::HesseFailed)
.def_property_readonly("hesse_failed", hesse_failed_workaround)
.def_property_readonly("has_covariance", &FunctionMinimum::HasCovariance)
.def_property_readonly("is_above_max_edm", &FunctionMinimum::IsAboveMaxEdm)
.def_property_readonly("has_reached_call_limit",
Expand Down
49 changes: 12 additions & 37 deletions src/iminuit/_repr_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,26 +93,30 @@ def good(x, should_be, alt_style=bad_style):

def fmin(fm):
ff = fmin_fields(fm)
if fm.hesse_failed:
cov_style = bad_style
elif fm.has_accurate_covar:
cov_style = good_style
else:
cov_style = warn_style
return to_str(
table(
tr(
th(
ff[0],
colspan=5,
colspan=2,
style="text-align:center",
title="Minimizer",
),
),
tr(
td(
ff[1],
colspan=2,
style="text-align:left",
title="Minimum value of function",
),
td(
ff[2],
colspan=3,
style="text-align:center",
title=(
"Total number of function and (optional) gradient evaluations"
Expand All @@ -122,68 +126,39 @@ def fmin(fm):
tr(
td(
ff[3],
colspan=2,
style="text-align:left",
title="Estimated distance to minimum and goal",
),
td(
ff[4],
colspan=3,
style="text-align:center",
title="Total run time of algorithms",
),
),
tr(
td(
ff[5],
colspan=2,
style="text-align:center;" + good(fm.is_valid, True),
),
td(
ff[6],
colspan=3,
style="text-align:center;"
+ good(fm.has_parameters_at_limit, False, warn_style),
style="text-align:center;" + good(fm.is_above_max_edm, False),
),
),
tr(
td(
ff[7],
colspan="2",
style="text-align:center;" + good(fm.is_above_max_edm, False),
style="text-align:center;"
+ good(fm.has_parameters_at_limit, False, warn_style),
),
td(
ff[8],
colspan=3,
style="text-align:center;" + good(fm.has_reached_call_limit, False),
),
),
tr(
td(
ff[9],
style="text-align:center;"
+ good(fm.has_covariance, True, warn_style),
),
td(
ff[10],
style="text-align:center;" + good(fm.hesse_failed, False),
),
td(
ff[11],
title="Is covariance matrix accurate?",
style="text-align:center;"
+ good(fm.has_accurate_covar, True, warn_style),
),
td(
ff[12],
style="text-align:center;" + good(fm.has_posdef_covar, True),
title="Is covariance matrix positive definite?",
),
td(
ff[13],
style="text-align:center;" + good(fm.has_made_posdef_covar, False),
title="Was positive definiteness enforced by Minuit?",
),
td(ff[9], style="text-align:center;" + cov_style),
td(ff[10], style="text-align:center;" + cov_style),
),
)
)
Expand Down
39 changes: 28 additions & 11 deletions src/iminuit/_repr_text.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,39 @@ def fmin_fields(fm):
s_ncall = f"Nfcn = {fm.nfcn}"
if fm.ngrad > 0:
s_ncall += f", Ngrad = {fm.ngrad}"

if fm.hesse_failed:
covariance_msg1 = "Hesse FAILED"
if fm.has_reached_call_limit:
covariance_msg2 = "ABOVE call limit"
else:
assert not fm.has_posdef_covar
covariance_msg2 = "Covariance NOT pos. def."
else:
if fm.has_covariance:
covariance_msg1 = "Hesse ok"
if fm.has_accurate_covar:
covariance_msg2 = "Covariance accurate"
elif fm.has_made_posdef_covar:
covariance_msg2 = "Covariance FORCED pos. def."
else:
covariance_msg2 = "Covariance APPROXIMATE"
else:
covariance_msg1 = "Hesse not run"
covariance_msg2 = "NO covariance"

return [
f"{fm.algorithm}",
f"FCN = {fm.fval:.4g}" + (f" (χ²/ndof = {rc:.1f})" if not np.isnan(rc) else ""),
s_ncall,
f"EDM = {fm.edm:.3g} (Goal: {fm.edm_goal:.3g})",
f"time = {fm.time:.1f} sec" if fm.time >= 0.1 else "",
f"{'Valid' if fm.is_valid else 'INVALID'} Minimum",
f"{'SOME' if fm.has_parameters_at_limit else 'No'} Parameters at limit",
f"{'ABOVE' if fm.is_above_max_edm else 'Below'} EDM threshold (goal x 10)",
f"{'SOME' if fm.has_parameters_at_limit else 'No'} parameters at limit",
f"{'ABOVE' if fm.has_reached_call_limit else 'Below'} call limit",
f"{'' if fm.has_covariance else 'NO '}Covariance",
f"Hesse {'FAILED' if fm.hesse_failed else 'ok'}",
"Accurate" if fm.has_accurate_covar else "APPROXIMATE",
"Pos. def." if fm.has_posdef_covar else "NOT pos. def.",
"FORCED" if fm.has_made_posdef_covar else "Not forced",
covariance_msg1,
covariance_msg2,
]


Expand All @@ -82,11 +100,10 @@ def fmin(fm):
l3 = format_line(w, "├┼┤")
v1 = format_row(w, *ff[5:7])
l4 = format_line(w, "├┼┤")
v2 = format_row((34, 38), *ff[7:9])
w = (15, 18, 11, 13, 12)
l5 = format_line(w, "├┬┼┬┬┤")
v3 = format_row(w, *ff[9:14])
l6 = format_line(w, "└┴┴┴┴┘")
v2 = format_row(w, *ff[7:9])
l5 = format_line(w, "├┼┤")
v3 = format_row(w, *ff[9:])
l6 = format_line(w, "└┴┘")
return "\n".join((l1, i1, l2, i2, i3, l3, v1, l4, v2, l5, v3, l6))


Expand Down
12 changes: 12 additions & 0 deletions tests/fmin_approximate.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
┌─────────────────────────────────────────────────────────────────────────┐
│ Migrad │
├──────────────────────────────────┬──────────────────────────────────────┤
│ FCN = 11.46 (χ²/ndof = 1.1) │ Nfcn = 10, Ngrad = 3 │
│ EDM = 1.23e-10 (Goal: 0.0001) │ │
├──────────────────────────────────┼──────────────────────────────────────┤
│ Valid Minimum │ Below EDM threshold (goal x 10) │
├──────────────────────────────────┼──────────────────────────────────────┤
│ No parameters at limit │ Below call limit │
├──────────────────────────────────┼──────────────────────────────────────┤
│ Hesse ok │ Covariance APPROXIMATE │
└──────────────────────────────────┴──────────────────────────────────────┘
23 changes: 10 additions & 13 deletions tests/fmin_bad.html
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
<table>
<tr>
<th colspan="5" style="text-align:center" title="Minimizer"> SciPy[L-BFGS-B] </th>
<th colspan="2" style="text-align:center" title="Minimizer"> SciPy[L-BFGS-B] </th>
</tr>
<tr>
<td colspan="2" style="text-align:left" title="Minimum value of function"> FCN = nan </td>
<td colspan="3" style="text-align:center" title="Total number of function and (optional) gradient evaluations"> Nfcn = 100000, Ngrad = 200000 </td>
<td style="text-align:left" title="Minimum value of function"> FCN = nan </td>
<td style="text-align:center" title="Total number of function and (optional) gradient evaluations"> Nfcn = 100000, Ngrad = 200000 </td>
</tr>
<tr>
<td colspan="2" style="text-align:left" title="Estimated distance to minimum and goal"> EDM = 1.23e-10 (Goal: 1e-05) </td>
<td colspan="3" style="text-align:center" title="Total run time of algorithms"> time = 1.2 sec </td>
<td style="text-align:left" title="Estimated distance to minimum and goal"> EDM = 1.23e-10 (Goal: 1e-05) </td>
<td style="text-align:center" title="Total run time of algorithms"> time = 1.2 sec </td>
</tr>
<tr>
<td colspan="2" style="text-align:center;{bad}"> INVALID Minimum </td>
<td colspan="3" style="text-align:center;{warn}"> SOME Parameters at limit </td>
<td style="text-align:center;{bad}"> INVALID Minimum </td>
<td style="text-align:center;{bad}"> ABOVE EDM threshold (goal x 10) </td>
</tr>
<tr>
<td colspan="2" style="text-align:center;{bad}"> ABOVE EDM threshold (goal x 10) </td>
<td colspan="3" style="text-align:center;{bad}"> ABOVE call limit </td>
<td style="text-align:center;{warn}"> SOME parameters at limit </td>
<td style="text-align:center;{bad}"> ABOVE call limit </td>
</tr>
<tr>
<td style="text-align:center;{warn}"> NO Covariance </td>
<td style="text-align:center;{bad}"> Hesse FAILED </td>
<td style="text-align:center;{warn}" title="Is covariance matrix accurate?"> APPROXIMATE </td>
<td style="text-align:center;{bad}" title="Is covariance matrix positive definite?"> NOT pos. def. </td>
<td style="text-align:center;{bad}" title="Was positive definiteness enforced by Minuit?"> FORCED </td>
<td style="text-align:center;{bad}"> ABOVE call limit </td>
</tr>
</table>
10 changes: 5 additions & 5 deletions tests/fmin_bad.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
│ FCN = nan │ Nfcn = 100000, Ngrad = 200000 │
│ EDM = 1.23e-10 (Goal: 1e-05) │ time = 1.2 sec │
├──────────────────────────────────┼──────────────────────────────────────┤
│ INVALID Minimum │ SOME Parameters at limit
│ INVALID Minimum │ ABOVE EDM threshold (goal x 10)
├──────────────────────────────────┼──────────────────────────────────────┤
ABOVE EDM threshold (goal x 10) │ ABOVE call limit │
├─────────────────────────────────┼────────────────────────────────────┤
NO Covariance │ Hesse FAILED │APPROXIMATE│NOT pos. def.FORCED
└─────────────────────────────────┴────────────────────────────────────┘
SOME parameters at limit │ ABOVE call limit │
├─────────────────────────────────┼──────────────────────────────────────┤
Hesse FAILED ABOVE call limit
└─────────────────────────────────┴──────────────────────────────────────┘
23 changes: 10 additions & 13 deletions tests/fmin_good.html
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
<table>
<tr>
<th colspan="5" style="text-align:center" title="Minimizer"> Migrad </th>
<th colspan="2" style="text-align:center" title="Minimizer"> Migrad </th>
</tr>
<tr>
<td colspan="2" style="text-align:left" title="Minimum value of function"> FCN = 11.46 (χ²/ndof = 1.1) </td>
<td colspan="3" style="text-align:center" title="Total number of function and (optional) gradient evaluations"> Nfcn = 10, Ngrad = 3 </td>
<td style="text-align:left" title="Minimum value of function"> FCN = 11.46 (χ²/ndof = 1.1) </td>
<td style="text-align:center" title="Total number of function and (optional) gradient evaluations"> Nfcn = 10, Ngrad = 3 </td>
</tr>
<tr>
<td colspan="2" style="text-align:left" title="Estimated distance to minimum and goal"> EDM = 1.23e-10 (Goal: 0.0001) </td>
<td colspan="3" style="text-align:center" title="Total run time of algorithms"> </td>
<td style="text-align:left" title="Estimated distance to minimum and goal"> EDM = 1.23e-10 (Goal: 0.0001) </td>
<td style="text-align:center" title="Total run time of algorithms"> </td>
</tr>
<tr>
<td colspan="2" style="text-align:center;{good}"> Valid Minimum </td>
<td colspan="3" style="text-align:center;{good}"> No Parameters at limit </td>
<td style="text-align:center;{good}"> Valid Minimum </td>
<td style="text-align:center;{good}"> Below EDM threshold (goal x 10) </td>
</tr>
<tr>
<td colspan="2" style="text-align:center;{good}"> Below EDM threshold (goal x 10) </td>
<td colspan="3" style="text-align:center;{good}"> Below call limit </td>
<td style="text-align:center;{good}"> No parameters at limit </td>
<td style="text-align:center;{good}"> Below call limit </td>
</tr>
<tr>
<td style="text-align:center;{good}"> Covariance </td>
<td style="text-align:center;{good}"> Hesse ok </td>
<td style="text-align:center;{good}" title="Is covariance matrix accurate?"> Accurate </td>
<td style="text-align:center;{good}" title="Is covariance matrix positive definite?"> Pos. def. </td>
<td style="text-align:center;{good}" title="Was positive definiteness enforced by Minuit?"> Not forced </td>
<td style="text-align:center;{good}"> Covariance accurate </td>
</tr>
</table>
10 changes: 5 additions & 5 deletions tests/fmin_good.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
│ FCN = 11.46 (χ²/ndof = 1.1) │ Nfcn = 10, Ngrad = 3 │
│ EDM = 1.23e-10 (Goal: 0.0001) │ │
├──────────────────────────────────┼──────────────────────────────────────┤
│ Valid Minimum │ No Parameters at limit
│ Valid Minimum │ Below EDM threshold (goal x 10)
├──────────────────────────────────┼──────────────────────────────────────┤
Below EDM threshold (goal x 10) │ Below call limit │
├─────────────────────────────────┼────────────────────────────────────┤
Covariance Hesse ok │ Accurate │ Pos. def.Not forced
└─────────────────────────────────┴────────────────────────────────────┘
No parameters at limit │ Below call limit │
├─────────────────────────────────┼──────────────────────────────────────┤
Hesse ok Covariance accurate
└─────────────────────────────────┴──────────────────────────────────────┘
Loading