Coveralls logob
Coveralls logo
  • Home
  • Features
  • Pricing
  • Docs
  • Sign In

fitbenchmarking / fitbenchmarking / 2330948078

16 May 2022 - 2:26 coverage decreased (-0.2%) to 86.542%
2330948078

Pull #1036

github

GitHub
Merge f94846412 into ed08b4d37
Pull Request #1036: Enable max runtime in curve fitting

0 of 46 new or added lines in 6 files covered. (0.0%)

5 existing lines in 4 files now uncovered.

3421 of 3953 relevant lines covered (86.54%)

0.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/fitbenchmarking/controllers/matlab_mixin.py
1
"""
2
Implements mixin class for the matlab fitting software controllers.
3
"""
4

5
import os
!
6
from tempfile import TemporaryDirectory
!
7

8
import matlab.engine
!
9

NEW
10
from fitbenchmarking.utils.exceptions import (IncompatibleProblemError,
!
11
                                              MissingSoftwareError)
12

13
try:
!
14
    import dill
!
15
    import_success = True
!
16
except ImportError:
!
17
    import_success = False
!
18

NEW
19
try:
!
NEW
20
    eng = matlab.engine.connect_matlab(name='FITBENCHMARKING_MATLAB')
!
NEW
21
except matlab.engine.EngineError:
!
NEW
22
    eng = matlab.engine.start_matlab()
!
NEW
23
    eng.matlab.engine.shareEngine('FITBENCHMARKING_MATLAB', nargout=0)
!
24

25

26
# If we re-implement caching, make sure the cache is cleared by the
27
# matlab controllers to avoid unwanted errors.
28
class MatlabMixin:
!
29
    """
30
    Mixin class for matlab fitting software controllers
31
    """
32

NEW
33
    incompatible_problems = ['mantid']
!
34

UNCOV
35
    def __init__(self, cost_func):
!
36
        """
37
        Initialise anything that is needed specifically for matlab
38
        fitting software
39
        """
40

41
        super().__init__(cost_func)
!
42

43
        if not import_success:
!
44
            raise MissingSoftwareError('Requirements are missing for Matlab '
!
45
                                       'fitting, module "dill" is required.')
46

47
        self.initial_params_mat = None
!
NEW
48
        self.original_timer = None
!
NEW
49
        self.eng = eng
!
NEW
50
        self.pickle_error = None
!
51

NEW
52
        try:
!
NEW
53
            with TemporaryDirectory() as temp_dir:
!
NEW
54
                temp_file = os.path.join(temp_dir, 'temp.pickle')
!
NEW
55
                with open(temp_file, 'wb') as f:
!
NEW
56
                    dill.dump(cost_func, f)
!
NEW
57
                self.eng.workspace['temp_file'] = temp_file
!
NEW
58
                self.eng.evalc('cf_f = py.open(temp_file,"rb")')
!
NEW
59
                self.eng.evalc('global cf')
!
NEW
60
                self.eng.evalc('cf = py.dill.load(cf_f)')
!
NEW
61
                self.eng.evalc('cf_f.close()')
!
NEW
62
            self.setup_timer()
!
NEW
63
        except RuntimeError as e:
!
NEW
64
            self.pickle_error = e
!
65

NEW
66
    def _validate_problem_format(self):
!
NEW
67
        super()._validate_problem_format()
!
NEW
68
        if self.pickle_error is not None:
!
NEW
69
            raise IncompatibleProblemError(
!
70
                'Failed to load problem in MATLAB') from self.pickle_error
71

72
    def clear_matlab(self):
!
73
        """
74
        Clear the matlab instance, ready for the next setup.
75
        """
NEW
76
        self.eng.clear('variables', nargout=0)
!
NEW
77
        self.eng.evalc('global cf')
!
78
        if self.original_timer is not None:
!
79
            self.timer = self.original_timer
!
80
            self.original_timer = None
!
81

NEW
82
    def setup_timer(self):
!
83
        """
84
        Create an interface into the timer associated with the cost function.
85
        The timer will be created in the matlab engine as "timer" and must
86
        not be overridden, although this can be changed in this function if
87
        there's a conflict.
88

89
        This overrides the controller's timer so that it can be controlled from
90
        other parts of the code.
91
        """
NEW
92
        self.eng.evalc('timer = cf.problem.timer')
!
93
        if self.original_timer is None:
!
94
            self.original_timer = self.timer
!
95
        self.timer = MatlabTimerInterface('timer')
!
96

97
    def py_to_mat(self, func):
!
98
        """
99
        Get the named function from the matlab version of the cost function
100

101
        :param func: The name of the function to retrieve
102
        :type func: str
103
        """
NEW
104
        self.eng.evalc(f'fct = py.getattr(cf, "{func}");')
!
NEW
105
        return self.eng.workspace['fct']
!
106

107

108
class MatlabTimerInterface:
!
109
    """
110
    A timer to convert from matlab to the python timer.
111
    """
112

113
    def __init__(self, timer):
!
114
        """
115
        Initialiser for MatlabTimerInterface
116

117
        :param timer: The name of the timer in the matlab engine
118
        :type timer: str
119
        """
120
        self.timer = timer
!
121
        self.eng = eng
!
122

123
    def __getattr__(self, value):
!
124
        """
125
        Override attribute access to return a deferred function which will be
126
        done inside matlab when called.
127

128
        This will only work if no arguments are passed and no return value is
129
        required.
130

131
        E.g: self.start will become lambda: self.eng.evalc('timer.start()')
132

133
        :param value: The name of the attribute to access
134
        :type value: str
135
        :return: A function which will call the requested function in matlab
136
        :rtype: lambda
137
        """
138
        return lambda: self.eng.evalc(f'{self.timer}.{value}()')
!
Troubleshooting · Open an Issue · Sales · Support · ENTERPRISE · CAREERS · STATUS
BLOG · TWITTER · Legal & Privacy · Supported CI Services · What's a CI service? · Automated Testing

© 2022 Coveralls, Inc