Repository: fitbenchmarking/fitbenchmarking

Issue:
Expose more features in RALFit controller
RALFit can exploit higher order derivatives, and we don't take advantage of that in FitBenchmarking.  We should add extra options to the RALFit controller.

Discussion:
github-actions[bot]: ## Unit & System Test Results
    4 files  +    1      4 suites  +1   8m 28s [:stopwatch:](https://github.com/EnricoMi/publish-unit-test-result-action/blob/v1.20/README.md#the-symbols "duration of all tests") + 1m 3s
360 tests +    2  351 [:heavy_check_mark:](https://github.com/EnricoMi/publish-unit-test-result-action/blob/v1.20/README.md#the-symbols "passed tests") +    1    8 [:zzz:](https://github.com/EnricoMi/publish-unit-test-result-action/blob/v1.20/README.md#the-symbols "skipped / disabled tests") ±  0  1 [:x:](https://github.com/EnricoMi/publish-unit-test-result-action/blob/v1.20/README.md#the-symbols "failed tests") +1 
688 runs  +325  636 [:heavy_check_mark:](https://github.com/EnricoMi/publish-unit-test-result-action/blob/v1.20/README.md#the-symbols "passed tests") +286  50 [:zzz:](https://github.com/EnricoMi/publish-unit-test-result-action/blob/v1.20/README.md#the-symbols "skipped / disabled tests") +37  2 [:x:](https://github.com/EnricoMi/publish-unit-test-result-action/blob/v1.20/README.md#the-symbols "failed tests") +2 

For more details on these failures, see [this check](https://github.com/fitbenchmarking/fitbenchmarking/runs/9495730177).

Results for commit e53377cb. ± Comparison against base commit 4c602d44.

[test-results]:data:application/gzip;base64,H4sIANlfc2MC/02MSw7DIAwFrxKx7oIABtPLRIQQCTWfisCq6t1r1JJ0OePnebE5LuFg907dOnaUmE+YSnI57hshcCRBp1yPUvNGw1G8rwr6Sz3ik9T5McwuLiSuRUhpT2RqJpWtNjXiD1pSS32abxHavhVF4/+g39c1ZgIWQEpj/Gj6IAyAtc5J5IDKGxHGCSe0s7JCsPcHGx2KnAYBAAA=

coveralls: 
[![Coverage Status](https://coveralls.io/builds/54574003/badge)](https://coveralls.io/builds/54574003)

Coverage decreased (-0.2%) to 85.52% when pulling **631f0317c012e216f12950f6655d8f38c77686ef on 1078-enhanced-ralfit** into **3fa74abbd9dedf3b5ad5949fa95f2339bab9bffa on master**.


Patch:
diff --git a/docs/source/users/options/minimizer_option.rst b/docs/source/users/options/minimizer_option.rst
index eeda979c..a3a1df10 100644
--- a/docs/source/users/options/minimizer_option.rst
+++ b/docs/source/users/options/minimizer_option.rst
@@ -609,8 +609,17 @@ order derivatives are currently utilized in FitBenchmarking.
 
 * Gauss-Newton, trust region method (:code:`gn`)
 * Hybrid Newton/Gauss-Newton, trust region method (:code:`hybrid`)
+* Newton, trust region method (:code:`newton`)
+* Newton-tensor, trust region method (:code:`newton-tensor`)
 * Gauss-Newton, regularization (:code:`gn_reg`)
 * Hybrid Newton/Gauss-Newton, regularization (:code:`hybrid_reg`)
+* Newton, regularization (:code:`newton_reg`)
+* Newton-tensor, regularization (:code:`newton-tensor_reg`)
+
+Note that the Newton-tensor methods take significantly longer than the other
+options to run (but may give a better solution in some cases).  For this
+reason, they are not included in the default minimizers for RALFit, but
+must be turned on in the options file.
 
 **Links** `Github - RALFit <https://github.com/ralna/ralfit/>`__. RALFit's Documentation on: `Gauss-Newton/Hybrid models <https://ralfit.readthedocs.io/projects/Fortran/en/latest/method.html#the-models>`__,  `the trust region method <https://ralfit.readthedocs.io/projects/Fortran/en/latest/method.html#the-trust-region-method>`__ and  `The regularization method <https://ralfit.readthedocs.io/projects/C/en/latest/method.html#regularization>`__
 
diff --git a/fitbenchmarking/controllers/ralfit_controller.py b/fitbenchmarking/controllers/ralfit_controller.py
index 00c1acac..46ba1aac 100644
--- a/fitbenchmarking/controllers/ralfit_controller.py
+++ b/fitbenchmarking/controllers/ralfit_controller.py
@@ -16,12 +16,14 @@ class RALFitController(Controller):
     """
 
     algorithm_check = {
-            'all': ['gn', 'hybrid', 'gn_reg', 'hybrid_reg'],
-            'ls': ['gn', 'hybrid', 'gn_reg', 'hybrid_reg'],
+            'all': ['gn', 'hybrid', 'newton', 'newton-tensor',
+                    'gn_reg', 'hybrid_reg', 'newton_reg', 'newton-tensor_reg'],
+            'ls': ['gn', 'hybrid', 'newton', 'newton-tensor',
+                   'gn_reg', 'hybrid_reg', 'newton_reg', 'newton-tensor_reg'],
             'deriv_free': [],
             'general': [],
             'simplex': [],
-            'trust_region': ['gn', 'hybrid'],
+            'trust_region': ['gn', 'hybrid', 'newton', 'newton-tensor'],
             'levenberg-marquardt': ['gn', 'gn_reg'],
             'gauss_newton': ['gn', 'gn_reg'],
             'bfgs': [],
@@ -29,9 +31,12 @@ class RALFitController(Controller):
             'steepest_descent': [],
             'global_optimization': []}
 
-    jacobian_enabled_solvers = ['gn', 'hybrid', 'gn_reg', 'hybrid_reg']
+    jacobian_enabled_solvers = ['gn', 'hybrid', 'newton', 'newton-tensor',
+                                'gn_reg', 'hybrid_reg', 'newton_reg',
+                                'newton-tensor_reg']
 
-    hessian_enabled_solvers = ['hybrid', 'hybrid_reg']
+    hessian_enabled_solvers = ['hybrid', 'newton', 'newton-tensor',
+                               'hybrid_reg', 'newton_reg', 'newton-tensor_reg']
 
     def __init__(self, cost_func):
         """
@@ -49,6 +54,7 @@ class RALFitController(Controller):
         self._popt = None
         self._options = {}
 
+    # pylint: disable=too-many-branches
     def setup(self):
         """
         Setup for RALFit
@@ -69,6 +75,18 @@ class RALFitController(Controller):
         elif self.minimizer == "hybrid_reg":
             self._options[b"model"] = 3
             self._options[b"type_of_method"] = 2
+        elif self.minimizer == "newton":
+            self._options[b"model"] = 2
+            self._options[b"type_of_method"] = 1
+        elif self.minimizer == "newton_reg":
+            self._options[b"model"] = 2
+            self._options[b"type_of_method"] = 2
+        elif self.minimizer == "newton-tensor":
+            self._options[b"model"] = 4
+            self._options[b"type_of_method"] = 1
+        elif self.minimizer == "newton-tensor_reg":
+            self._options[b"model"] = 4
+            self._options[b"type_of_method"] = 2
         else:
             raise UnknownMinimizerError(
                 "No {} minimizer for RALFit".format(self.minimizer))
@@ -89,6 +107,7 @@ class RALFitController(Controller):
             self.param_ranges = (
                 [-np.inf]*len(self.initial_params),
                 [np.inf]*len(self.initial_params))
+    # pylint: enable=too-many-branches
 
     # pylint: disable=unused-argument
     def hes_eval(self, params, r):
diff --git a/fitbenchmarking/utils/options.py b/fitbenchmarking/utils/options.py
index 01779405..3bfaf8df 100644
--- a/fitbenchmarking/utils/options.py
+++ b/fitbenchmarking/utils/options.py
@@ -79,7 +79,9 @@ class Options:
          'matlab_opt': ['levenberg-marquardt', 'trust-region-reflective'],
          'matlab_stats': ['Levenberg-Marquardt'],
          'minuit': ['minuit'],
-         'ralfit': ['gn', 'gn_reg', 'hybrid', 'hybrid_reg'],
+         'ralfit': ['gn', 'gn_reg', 'hybrid', 'hybrid_reg',
+                    'newton', 'newton_reg',
+                    'newton-tensor', 'newton-tensor_reg'],
          'scipy': ['Nelder-Mead',
                    'Powell',
                    'CG',
@@ -195,7 +197,8 @@ class Options:
          'matlab_opt': ['levenberg-marquardt', 'trust-region-reflective'],
          'matlab_stats': ['Levenberg-Marquardt'],
          'minuit': ['minuit'],
-         'ralfit': ['gn', 'gn_reg', 'hybrid', 'hybrid_reg'],
+         'ralfit': ['gn', 'gn_reg', 'hybrid', 'hybrid_reg',
+                    'newton', 'newton_reg'],
          'scipy': ['Nelder-Mead',
                    'Powell',
                    'CG',


Test patch:
diff --git a/fitbenchmarking/utils/tests/test_options_minimizers.py b/fitbenchmarking/utils/tests/test_options_minimizers.py
index 2cb7ade5..4e7fccdf 100644
--- a/fitbenchmarking/utils/tests/test_options_minimizers.py
+++ b/fitbenchmarking/utils/tests/test_options_minimizers.py
@@ -75,7 +75,8 @@ class MininimizerOptionTests(unittest.TestCase):
         """
         Checks valid ralfit minimizers are set correctly
         """
-        expected = ['gn', 'gn_reg', 'hybrid', 'hybrid_reg']
+        expected = ['gn', 'gn_reg', 'hybrid', 'hybrid_reg',
+                    'newton', 'newton_reg']
         actual = self.options.minimizers['ralfit']
         self.assertEqual(expected, actual)