-
Notifications
You must be signed in to change notification settings - Fork 4
/
test_fitting_benchmarking_jacobians.py
145 lines (123 loc) · 4.82 KB
/
test_fitting_benchmarking_jacobians.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
"""
Tests for fitbenchmarking.core.fitting_benchmarking.loop_over_jacobians
"""
import inspect
import os
import unittest
from unittest.mock import patch
from fitbenchmarking import test_files
from fitbenchmarking.controllers.base_controller import Controller
from fitbenchmarking.core.fitting_benchmarking import loop_over_jacobians
from fitbenchmarking.cost_func.nlls_cost_func import NLLSCostFunc
from fitbenchmarking.parsing.parser_factory import parse_problem_file
from fitbenchmarking.utils import output_grabber
from fitbenchmarking.utils.checkpoint import Checkpoint
from fitbenchmarking.utils.options import Options
# Due to construction of the controllers two folder functions
# pylint: disable=unnecessary-pass
# Defines the module which we mock out certain function calls for
FITTING_DIR = "fitbenchmarking.core.fitting_benchmarking"
class DummyController(Controller):
"""
Minimal instantiatable subclass of Controller class for testing
"""
def __init__(self, cost_func):
"""
Initialize dummy controller
:param cost_func: cost function class
:type cost_func: CostFunc class
"""
super().__init__(cost_func)
self.algorithm_check = {'all': ['deriv_free_algorithm', 'general'],
'ls': [None],
'deriv_free': ['deriv_free_algorithm'],
'general': ['general']}
self.final_params_expected = [[1, 2, 3, 4], [4, 3, 2, 1]]
self.flag_expected = [0, 1]
self.count = 0
self.jacobian_enabled_solvers = ["general"]
self.hessian_enabled_solvers = []
def setup(self):
"""
Mock controller setup function
"""
pass
def fit(self):
"""
Mock controller fit function
"""
pass
def cleanup(self):
"""
Mock controller cleanup function
"""
self.final_params = self.final_params_expected[self.count]
self.flag = self.flag_expected[self.count]
self.count += 1
self.count = self.count % len(self.flag_expected)
def make_cost_function(file_name='cubic.dat', minimizers=None):
"""
Helper function that returns a simple fitting problem
"""
options = Options()
if minimizers:
options.minimizers = minimizers
bench_prob_dir = os.path.dirname(inspect.getfile(test_files))
fname = os.path.join(bench_prob_dir, file_name)
fitting_problem = parse_problem_file(fname, options)
fitting_problem.correct_data()
cost_func = NLLSCostFunc(fitting_problem)
return cost_func
class LoopOverJacobiansTests(unittest.TestCase):
"""
loop_over_jacobians tests
"""
def setUp(self):
"""
Setting up problem for tests
"""
self.minimizers = ["deriv_free_algorithm", "general"]
self.cost_func = make_cost_function(minimizers=self.minimizers)
self.problem = self.cost_func.problem
self.controller = DummyController(cost_func=self.cost_func)
self.options = self.problem.options
self.grabbed_output = output_grabber.OutputGrabber(self.options)
self.cp = Checkpoint(self.options)
@staticmethod
def mock_func_call(*args, **kwargs):
"""
Mock function to be used instead of loop_over_hessians
"""
return []
@patch(f'{FITTING_DIR}.loop_over_hessians')
def test_single_jacobian(self, loop_over_hessians):
"""
Test to check that only one Jacobian option has been added
"""
self.options.jac_method = ["scipy"]
self.options.jac_num_method = {"scipy": ["3-point"]}
self.controller.minimizer = "general"
loop_over_hessians.side_effect = self.mock_func_call
_ = loop_over_jacobians(self.controller,
options=self.options,
grabbed_output=self.grabbed_output,
checkpointer=self.cp,
emissions_tracker=None)
loop_over_hessians.assert_called_once()
@patch(f'{FITTING_DIR}.loop_over_hessians')
def test_multiple_jacobian(self, loop_over_hessians):
"""
Test to check multiple Jacobian options are set correctly
"""
self.options.jac_method = ["scipy"]
self.options.jac_num_method = {"scipy": ["3-point", "2-point"]}
self.controller.minimizer = "general"
loop_over_hessians.side_effect = self.mock_func_call
_ = loop_over_jacobians(self.controller,
options=self.options,
grabbed_output=self.grabbed_output,
checkpointer=self.cp,
emissions_tracker=None)
self.assertEqual(loop_over_hessians.call_count, 2)
if __name__ == "__main__":
unittest.main()