Updated Why multistart misses solutions (markdown)
Stop methods2.py hanging on the n=1000 tunneling run As committed the script would spend ~37 minutes on a single tunneling solve at n = 1000 with no warning, and lost all results if interrupted because the JSON was only written at the very end. Put that run behind RUN_TUNNELING_N1000 (default off, with the cost model in a comment) and dump results incrementally. Adds the methods2.json the page's threshold and cost tables are drawn from.
Sharpen the tunneling cost claim with the O(n^3) model The n=1000 tunneling run was abandoned after 30 minutes rather than 15; state the measured bound and the cost model that predicts ~37 min.
Add: Why multistart misses solutions A worked demonstration that multistart's chance of finding a minimum is that minimum's basin measure under the sampler, and that the measure collapses exponentially in n. Built on an NLP with exactly two minima -- one broad valley, one narrow slot -- where uniform multistart at n = 1000 would need ~1e22 starts and deflation finds both in five solves. Also covers: a fair comparison of all six find_minima strategies with each scale knob swept; why basinhopping and MLSL fail structurally rather than through mistuning; and the L2 pole scaling that deflation needs on any discretised problem.
Add the POUNCE half: a printed zero is not always a measurement The page now warns that Ipopt's bound-violation line covers variable bounds only. The companion fact is that a zero on that row may not be a reading at all: POUNCE's identically-named row was a hardcoded constant through 0.10.0, with a rationale that confused the box the solver was handed for the box the caller declared. Fixed as gh#900; POUNCE now measures it on both arms and prints the declared-model violation, constraint rows included, in bold red. Also notes that feasibility check 1 was computed from the problem data, not read off a solver's own row.
Add the Ipopt-side fix, and correct the "watch the log" advice Answers the question the page raised but never closed: Ipopt has the same knob. Measured on 3.14.19/MUMPS, `bound_relax_factor 0` takes the toy problem from -0.99999 to 9.1e-06, LISWET1 from 27.12208 to 36.12999 (25% error -> 2.1e-04) and YAO from 196.17712 to 197.70426 (0.77% -> 2.1e-07). Also records that `honor_original_bounds` is not that fix — it returns x = 0 on the toy problem while still reporting the objective -0.99999 from the unprojected point, and on LISWET1 it changes nothing at all, because projection touches variable bounds and LISWET1's pressure is on general rows. That last fact contradicted takeaway 2. "Check the bound-violation line" is sound on the toy problem and useless on LISWET1, whose default run prints zero for every violation it reports and is still 25% low. The line covers variable bounds only, and is itself new in Ipopt 3.14. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B4TwrLpRgNvdowBTAtt2kP
Add "A hair's width times a cliff" and link it from Home Explains why POUNCE and Ipopt-MA57 disagree on the LISWET/YAO family of convex QPs while both report Optimal Solution Found, using a one-variable problem with an analytic solution at the origin as the worked example. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T5FT9tv37YwUgCVhhjTvTb
Add a page on recovering from bad and degenerate starting points What to do when a solve fails because of where it started: whether the starting point is even the cause, an atlas of twelve ways a start kills a solve, and an ordered ladder of recovery moves. Five worked examples measured on POUNCE 0.10.0 and cross-checked between the CLI and the Python frontend. A feasible three-component flash written with no Var.value set spends three solves and 72 iterations reaching Infeasible_Problem_Detected, and solves in 4 after initialize_missing_values -- the second-opinion ladder cannot rescue it because every rung varies the algorithm and none varies the point. On an entropy model with a closed form, starting at the origin drives gradient-based scaling to its nlp_scaling_min_value floor, and only nlp_scaling_method=none recovers the accuracy (5.6e-17 against 1.3e-09), exactly matching a sane start. Two nulls are reported as nulls: bound_push swept over four orders on an at-the-bound start is 6-7 iterations throughout, and least_square_init_primal driving an initial violation of 9.997e11 to exactly zero turns one clean 29-iteration solve into three (4, 4, 20). Atlas rows without a measurement are marked (unmeasured).
Add per-problem option tuning guide Measured guidance for choosing POUNCE solver options, from a study of ten non-default options across all 47 problems of the Mittelmann ampl-nlp suite (595 solves; every claimed win re-timed and independently verified). Covers: why there is no globally good setting, how to diagnose a model before picking options, a symptom-to-lever table, what each option measurably did across the suite, four worked examples predicted from the diagnosis before being measured, and one case where near-identical structure gave the opposite result. Links the defect and documentation findings to the repository rather than restating them here.
Initial Home page