Repository: scipy/scipy
Pull request: BUG: fix `scipy.optimize.show_options` for unknown methods. and add *_METHODS list for each solver script and fix show_options doc
<!-- 
Thanks for contributing a pull request! Please ensure that
your PR satisfies the checklist before submitting:
http://scipy.github.io/devdocs/dev/contributor/development_workflow.html#checklist-before-submitting-a-pr

Also, please name and describe your PR as you would write a
commit message:
https://docs.scipy.org/doc/numpy/dev/development_workflow.html#writing-the-commit-message

Note that we are a team of volunteers; we appreciate your
patience during the review process.

Again, thanks for contributing!
-->

#### Reference issue
fix #10782 

#### What does this implement/fix?
I fixed `scipy.optimize.show_options` for unknown methods and added a test for it.
I added a global *_METHODS list for each solver script which is proposed in #10782 
I fixed `show_options` docstring because it is missing `scipy.optimize.root_scalar` doc links.


Problem statement:
BUG: optimize: methods unknown to `scipy.optimize.show_options`
Some `scipy.optimize.minimize` and `scipy.optimize.linprog` solvers aren't known to `scipy.optimize.show_options`.

#### Reproducing code example:
<!-- 
If you place your code between the triple backticks below, 
it will be rendered as a code block. 
-->

```
from scipy.optimize import show_options
show_options('minimize', 'trust-ncg')  # OK
show_options('minimize', 'trust-constr')  # not OK
show_options('linprog', 'interior-point')  # OK
show_options('linprog', 'revised simplex')  # not OK
```



#### Error message:
<!-- If any, paste the *full* error message inside a code block
as above (starting from line Traceback)
-->

```
Traceback (most recent call last):

  File "<ipython-input-9-2adcf805db05>", line 1, in <module>
    show_options('linprog', 'revised simplex')

  File "C:\Users\mhaberla\AppData\Local\Continuum\anaconda3\lib\site-packages\scipy\optimize\optimize.py", line 3104, in show_options
    raise ValueError("Unknown method %r" % (method,))

ValueError: Unknown method 'revised simplex'
  ...
```

#### Scipy/Numpy/Python version information:
```
1.3.0 1.16.4 sys.version_info(major=3, minor=7, micro=4, releaselevel='final', serial=0)
```

Hints from issue discussion:
This can be fixed by adding the required information to [`optimize.py` `show_options`](https://github.com/scipy/scipy/blob/master/scipy/optimize/optimize.py).

Should probably add a test like:
```
solver_methods = {'linprog':['simplex', 'revised simplex', 'interior-point']} 
for solver, methods in solver_methods.items():
    for method in methods:
        show_options(solver, method)
```
to make sure there are no errors, except that the method names should not be hard-coded into the test itself, rather imported from a list in the solver's main file as proposed in gh-10763.

Commit message: fix lint error

Patch to review:
diff --git a/scipy/optimize/_linprog.py b/scipy/optimize/_linprog.py
index 1d9ca90d7bed..dbe0d21b3e34 100644
--- a/scipy/optimize/_linprog.py
+++ b/scipy/optimize/_linprog.py
@@ -31,6 +31,8 @@
 
 __docformat__ = "restructuredtext en"
 
+LINPROG_METHODS = ['simplex', 'revised simplex', 'interior-point']
+
 
 def linprog_verbose_callback(res):
     """
diff --git a/scipy/optimize/_minimize.py b/scipy/optimize/_minimize.py
index 65db509e2a35..bfa065d19282 100644
--- a/scipy/optimize/_minimize.py
+++ b/scipy/optimize/_minimize.py
@@ -40,6 +40,7 @@
                     'l-bfgs-b', 'tnc', 'cobyla', 'slsqp', 'trust-constr',
                     'dogleg', 'trust-ncg', 'trust-exact', 'trust-krylov']
 
+MINIMIZE_SCALAR_METHODS = ['Brent', 'Bounded', 'Golden']
 
 def minimize(fun, x0, args=(), method=None, jac=None, hess=None,
              hessp=None, bounds=None, constraints=(), tol=None,
diff --git a/scipy/optimize/_qap.py b/scipy/optimize/_qap.py
index 4c056a3eba91..54cf0fd51d37 100644
--- a/scipy/optimize/_qap.py
+++ b/scipy/optimize/_qap.py
@@ -6,6 +6,7 @@
 from scipy._lib._util import check_random_state
 import itertools
 
+QUADRATIC_ASSIGNMENT_METHODS = ['faq', '2opt']
 
 def quadratic_assignment(A, B, method="faq", options=None):
     r"""
diff --git a/scipy/optimize/_root.py b/scipy/optimize/_root.py
index 91d2e6c61fa5..af4e82e39619 100644
--- a/scipy/optimize/_root.py
+++ b/scipy/optimize/_root.py
@@ -9,6 +9,9 @@
 
 import numpy as np
 
+ROOT_METHODS = ['hybr', 'lm', 'broyden1', 'broyden2', 'anderson',
+                'linearmixing', 'diagbroyden', 'excitingmixing', 'krylov',
+                'df-sane']
 
 from warnings import warn
 
diff --git a/scipy/optimize/_root_scalar.py b/scipy/optimize/_root_scalar.py
index 5c6581c464fb..78786e287aed 100644
--- a/scipy/optimize/_root_scalar.py
+++ b/scipy/optimize/_root_scalar.py
@@ -12,6 +12,9 @@
 
 __all__ = ['root_scalar']
 
+ROOT_SCALAR_METHODS = ['bisect', 'brentq', 'brenth', 'ridder', 'toms748',
+                       'newton', 'secant', 'halley']
+
 
 class MemoizeDer(object):
     """Decorator that caches the value and derivative(s) of function each
diff --git a/scipy/optimize/optimize.py b/scipy/optimize/optimize.py
index e8100f9bf329..a9ee00fcbcdc 100644
--- a/scipy/optimize/optimize.py
+++ b/scipy/optimize/optimize.py
@@ -3396,6 +3396,17 @@ def show_options(solver=None, method=None, disp=True):
     - :ref:`golden      <optimize.minimize_scalar-golden>`
     - :ref:`bounded     <optimize.minimize_scalar-bounded>`
 
+    `scipy.optimize.root_scalar`
+
+    - :ref:`bisect  <optimize.root_scalar-bisect>`
+    - :ref:`brentq  <optimize.root_scalar-brentq>`
+    - :ref:`brenth  <optimize.root_scalar-brenth>`
+    - :ref:`ridder  <optimize.root_scalar-ridder>`
+    - :ref:`toms748 <optimize.root_scalar-toms748>`
+    - :ref:`newton  <optimize.root_scalar-newton>`
+    - :ref:`secant  <optimize.root_scalar-secant>`
+    - :ref:`halley  <optimize.root_scalar-halley>`
+
     `scipy.optimize.linprog`
 
     - :ref:`simplex         <optimize.linprog-simplex>`
@@ -3440,7 +3451,15 @@ def show_options(solver=None, method=None, disp=True):
             ('powell', 'scipy.optimize.optimize._minimize_powell'),
             ('slsqp', 'scipy.optimize.slsqp._minimize_slsqp'),
             ('tnc', 'scipy.optimize.tnc._minimize_tnc'),
-            ('trust-ncg', 'scipy.optimize._trustregion_ncg._minimize_trust_ncg'),
+            ('trust-ncg',
+             'scipy.optimize._trustregion_ncg._minimize_trust_ncg'),
+            ('trust-constr',
+             'scipy.optimize._trustregion_constr.'
+             '_minimize_trustregion_constr'),
+            ('trust-exact',
+             'scipy.optimize._trustregion_exact._minimize_trustregion_exact'),
+            ('trust-krylov',
+             'scipy.optimize._trustregion_krylov._minimize_trust_krylov'),
         ),
         'root': (
             ('hybr', 'scipy.optimize.minpack._root_hybr'),
diff --git a/scipy/optimize/tests/test_optimize.py b/scipy/optimize/tests/test_optimize.py
index d2c83906ee8a..490ace15c12f 100644
--- a/scipy/optimize/tests/test_optimize.py
+++ b/scipy/optimize/tests/test_optimize.py
@@ -19,9 +19,13 @@
 from pytest import raises as assert_raises
 
 from scipy import optimize
-from scipy.optimize._minimize import MINIMIZE_METHODS
+from scipy.optimize._minimize import MINIMIZE_METHODS, MINIMIZE_SCALAR_METHODS
+from scipy.optimize._linprog import LINPROG_METHODS
+from scipy.optimize._root import ROOT_METHODS
+from scipy.optimize._root_scalar import ROOT_SCALAR_METHODS
+from scipy.optimize._qap import QUADRATIC_ASSIGNMENT_METHODS
 from scipy.optimize._differentiable_functions import ScalarFunction
-from scipy.optimize.optimize import MemoizeJac
+from scipy.optimize.optimize import MemoizeJac, show_options
 
 
 def test_check_grad():
@@ -2174,8 +2178,23 @@ def test_memoize_jac_with_bfgs(function_with_gradient):
     scalar_function.fun(x0 + 0.2)
     assert function_with_gradient.number_of_calls == 3
 
+
 def test_gh12696():
     # Test that optimize doesn't throw warning gh-12696
     with assert_no_warnings():
         optimize.fminbound(
             lambda x: np.array([x**2]), -np.pi, np.pi, disp=False)
+
+
+def test_show_options():
+    solver_methods = {
+        'minimize': MINIMIZE_METHODS,
+        'minimize_scalar': MINIMIZE_SCALAR_METHODS,
+        'root': ROOT_METHODS,
+        'root_scalar': ROOT_SCALAR_METHODS,
+        'linprog': LINPROG_METHODS,
+        'quadratic_assignment': QUADRATIC_ASSIGNMENT_METHODS,
+    }
+    for solver, methods in solver_methods.items():
+        for method in methods:
+            show_options(solver, method)


Code review comments:
diff_hunk: @@ -31,6 +31,8 @@
 
 __docformat__ = "restructuredtext en"
 
+LINPROG_METHODS = ['simplex', 'revised simplex', 'interior-point']
path: scipy/optimize/_linprog.py
text: @user1:
```suggestion
LINPROG_METHODS = ['simplex', 'revised simplex', 'interior-point', 'highs', 'highs-ds', 'highs-ipm']
```

@user1:
Can you also add these to show_options?