Package user_functions :: Module minimisation
[hide private]
[frames] | no frames]

Source Code for Module user_functions.minimisation

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2002-2005,2008-2009,2012,2014,2019 Edward d'Auvergne          # 
  4  #                                                                             # 
  5  # This file is part of the program relax (http://www.nmr-relax.com).          # 
  6  #                                                                             # 
  7  # This program is free software: you can redistribute it and/or modify        # 
  8  # it under the terms of the GNU General Public License as published by        # 
  9  # the Free Software Foundation, either version 3 of the License, or           # 
 10  # (at your option) any later version.                                         # 
 11  #                                                                             # 
 12  # This program is distributed in the hope that it will be useful,             # 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 15  # GNU General Public License for more details.                                # 
 16  #                                                                             # 
 17  # You should have received a copy of the GNU General Public License           # 
 18  # along with this program.  If not, see <http://www.gnu.org/licenses/>.       # 
 19  #                                                                             # 
 20  ############################################################################### 
 21   
 22  # Module docstring. 
 23  """The minimisation user function definitions.""" 
 24   
 25  # relax module imports. 
 26  from graphics import WIZARD_IMAGE_PATH 
 27  from pipe_control import minimise 
 28  from user_functions.data import Uf_info, Uf_tables; uf_info = Uf_info(); uf_tables = Uf_tables() 
 29  from user_functions.objects import Desc_container 
 30   
 31   
 32  # The user function class. 
 33  uf_class = uf_info.add_class('minimise') 
 34  uf_class.title = "Class for setting parameter values." 
 35  uf_class.menu_text = "&minimise" 
 36  uf_class.gui_icon = "relax.rosenbrock" 
 37   
 38   
 39  # The minimise.calculate user function. 
 40  uf = uf_info.add_uf('minimise.calculate') 
 41  uf.title = "Calculate the model parameters or the current target function value." 
 42  uf.title_short = "Model parameter or target function value calculation." 
 43  uf.display = True 
 44  uf.add_keyarg( 
 45      name = "verbosity", 
 46      default = 1, 
 47      basic_types = ["int"], 
 48      desc_short = "verbosity level", 
 49      desc = "The amount of information to print to screen.  Zero corresponds to minimal output while higher values increase the amount of output.  The default value is 1." 
 50  ) 
 51  # Description. 
 52  uf.desc.append(Desc_container()) 
 53  uf.desc[-1].add_paragraph("The operation of this user function is two-fold and depends on whether the solution for the models of the current analysis are found by direct calculation or by optimisation.  The dual operations are:") 
 54  uf.desc[-1].add_item_list_element("Direct calculation models", "For these models, the parameters will be directly calculated from the base data.  This will be the exact solution and the user function will store the parameter values.  The grid search and optimisation user functions are not implemented for this analysis type.") 
 55  uf.desc[-1].add_item_list_element("Optimised models", "This will call the target function normally used for optimisation for each model using the current parameter values.  This can be used to manually find the chi-squared value for different parameter values.  The parameter values will not be affected.") 
 56  uf.backend = minimise.calc 
 57  uf.menu_text = "&calculate" 
 58  uf.gui_icon = "oxygen.categories.applications-education" 
 59  uf.wizard_size = (900, 500) 
 60  uf.wizard_image = WIZARD_IMAGE_PATH + 'minimise.png' 
 61   
 62   
 63  # The minimise.execute user function. 
 64  uf = uf_info.add_uf('minimise.execute') 
 65  uf.title = "Perform an optimisation." 
 66  uf.title_short = "Minimisation." 
 67  uf.display = True 
 68  uf.add_keyarg( 
 69      name = "min_algor", 
 70      default = "newton", 
 71      basic_types = ["str"], 
 72      desc_short = "minimisation algorithm", 
 73      desc = "The optimisation algorithm to use.", 
 74      wiz_element_type = 'combo', 
 75      wiz_combo_choices = [ 
 76          "Back-and-forth coordinate descent", 
 77          "Steepest descent", 
 78          "Quasi-Newton BFGS", 
 79          "Newton", 
 80          "Newton-CG", 
 81          "Cauchy point", 
 82          "Dogleg", 
 83          "CG-Steihaug", 
 84          "Exact trust region", 
 85          "Fletcher-Reeves", 
 86          "Polak-Ribiere", 
 87          "Polak-Ribiere +", 
 88          "Hestenes-Stiefel", 
 89          "Simplex", 
 90          "Levenberg-Marquardt", 
 91          "Simulated Annealing" 
 92      ], 
 93      wiz_combo_data = [ 
 94          "cd", 
 95          "sd", 
 96          "bfgs", 
 97          "newton", 
 98          "ncg", 
 99          "cauchy", 
100          "dogleg", 
101          "steihaug", 
102          "exact", 
103          "fr", 
104          "pr", 
105          "pr+", 
106          "hs", 
107          "simplex", 
108          "lm", 
109          "sa" 
110      ], 
111      wiz_read_only = True 
112  ) 
113  uf.add_keyarg( 
114      name = "line_search", 
115      basic_types = ["str"], 
116      desc_short = "line search algorithm", 
117      desc = "The line search algorithm which will only be used in combination with the line search and conjugate gradient methods.  This will default to the More and Thuente line search.", 
118      wiz_element_type = 'combo', 
119      wiz_combo_choices = [ 
120          "Backtracking", 
121          "Nocedal and Wright interpolation", 
122          "Nocedal and Wright for the Wolfe conditions", 
123          "More and Thuente", 
124          "No line search" 
125      ], 
126      wiz_combo_data = [ 
127          "back", 
128          "nwi", 
129          "nww", 
130          "mt", 
131          "no line" 
132      ], 
133      wiz_read_only = True, 
134      can_be_none = True 
135  ) 
136  uf.add_keyarg( 
137      name = "hessian_mod", 
138      basic_types = ["str"], 
139      desc_short = "hessian modification", 
140      desc = "The Hessian modification.  This will only be used in the algorithms which use the Hessian, and defaults to Gill, Murray, and Wright modified Cholesky algorithm.", 
141      wiz_element_type = 'combo', 
142      wiz_combo_choices = [ 
143          "Unmodified Hessian", 
144          "Eigenvalue modification", 
145          "Cholesky with added multiple of the identity", 
146          "The Gill, Murray, and Wright modified Cholesky algorithm", 
147          "The Schnabel and Eskow 1999 algorithm" 
148      ], 
149      wiz_combo_data = [ 
150          "no hessian mod", 
151          "eigen", 
152          "chol", 
153          "gmw", 
154          "se99" 
155      ], 
156      wiz_read_only = True, 
157      can_be_none = True 
158  ) 
159  uf.add_keyarg( 
160      name = "hessian_type", 
161      basic_types = ["str"], 
162      desc_short = "hessian type", 
163      desc = "The Hessian type.  This will only be used in a few trust region algorithms, and defaults to BFGS.", 
164      wiz_element_type = 'combo', 
165      wiz_combo_choices = [ 
166          "Quasi-Newton BFGS", 
167          "Newton" 
168      ], 
169      wiz_combo_data = [ 
170          "bfgs", 
171          "newton" 
172      ], 
173      wiz_read_only = True, 
174      can_be_none = True 
175  ) 
176  uf.add_keyarg( 
177      name = "func_tol", 
178      default = 1e-25, 
179      basic_types = ["float"], 
180      desc_short = "function tolerance", 
181      desc = "The function tolerance.  This is used to terminate minimisation once the function value between iterations is less than the tolerance.  The default value is 1e-25." 
182  ) 
183  uf.add_keyarg( 
184      name = "grad_tol", 
185      basic_types = ["float"], 
186      desc_short = "gradient tolerance", 
187      desc = "The gradient tolerance.  Minimisation is terminated if the current gradient value is less than the tolerance.  The default value is None.", 
188      can_be_none = True 
189  ) 
190  uf.add_keyarg( 
191      name = "max_iter", 
192      default = 10000000, 
193      basic_types = ["int"], 
194      min = 1, 
195      max = 1000000000, 
196      desc_short = "maximum number of iterations", 
197      desc = "The maximum number of iterations.  The default value is 1e7." 
198  ) 
199  uf.add_keyarg( 
200      name = "constraints", 
201      default = True, 
202      basic_types = ["bool"], 
203      desc_short = "constraints flag", 
204      desc = "A boolean flag specifying whether the parameters should be constrained.  The default is to turn constraints on (constraints=True)." 
205  ) 
206  uf.add_keyarg( 
207      name = "scaling", 
208      default = True, 
209      basic_types = ["bool"], 
210      desc_short = "diagonal scaling flag", 
211      desc = "The diagonal scaling boolean flag.  The default that scaling is on (scaling=True)." 
212  ) 
213  uf.add_keyarg( 
214      name = "verbosity", 
215      default = 1, 
216      basic_types = ["int"], 
217      desc_short = "verbosity level", 
218      desc = "The amount of information to print to screen.  Zero corresponds to minimal output while higher values increase the amount of output.  The default value is 1." 
219  ) 
220  # Description. 
221  uf.desc.append(Desc_container()) 
222  uf.desc[-1].add_paragraph("This will perform an optimisation starting from the current parameter values.  This is only suitable for data pipe types which have target functions and hence support optimisation.") 
223  # Diagonal scaling. 
224  uf.desc.append(Desc_container("Diagonal scaling")) 
225  uf.desc[-1].add_paragraph("Diagonal scaling is the transformation of parameter values such that each value has a similar order of magnitude.  Certain minimisation techniques, for example the trust region methods, perform extremely poorly with badly scaled problems.  In addition, methods which are insensitive to scaling such as Newton minimisation may still benefit due to the minimisation of round off errors.") 
226  uf.desc[-1].add_paragraph("In Model-free analysis for example, if S2 = 0.5, te = 200 ps, and Rex = 15 1/s at 600 MHz, the unscaled parameter vector would be [0.5, 2.0e-10, 1.055e-18].  Rex is divided by (2 * pi * 600,000,000)**2 to make it field strength independent.  The scaling vector for this model may be something like [1.0, 1e-9, 1/(2 * pi * 6e8)**2].  By dividing the unscaled parameter vector by the scaling vector the scaled parameter vector is [0.5, 0.2, 15.0].  To revert to the original unscaled parameter vector, the scaled parameter vector and scaling vector are multiplied.") 
227  # Minimisation algorithms. 
228  uf.desc.append(Desc_container("Minimisation algorithms")) 
229  uf.desc[-1].add_paragraph("A minimisation function is selected if the minimisation algorithm matches a certain pattern.  Because the python regular expression 'match' statement is used, various strings can be supplied to select the same minimisation algorithm.  Below is a list of the minimisation algorithms available together with the corresponding patterns.") 
230  uf.desc[-1].add_paragraph("This is a short description of python regular expression, for more information, see the regular expression syntax section of the Python Library Reference.  Some of the regular expression syntax used in this function is:") 
231  uf.desc[-1].add_item_list_element("'[]'", "A sequence or set of characters to match to a single character.  For example, '[Nn]ewton' will match both 'Newton' and 'newton'.") 
232  uf.desc[-1].add_item_list_element("'^'", "Match the start of the string.") 
233  uf.desc[-1].add_item_list_element("'$'", "Match the end of the string.  For example, '^[Ll][Mm]$' will match 'lm' and 'LM' but will not match if characters are placed either before or after these strings.") 
234  uf.desc[-1].add_paragraph("To select a minimisation algorithm, use a string which matches one of the following patterns given in the tables.") 
235  uf.desc[-1].add_paragraph("Unconstrained line search methods:") 
236  table = uf_tables.add_table(label="table: min - line search", caption="Minimisation algorithms -- unconstrained line search methods.") 
237  table.add_headings(["Minimisation algorithm", "Patterns"]) 
238  table.add_row(["Back-and-forth coordinate descent", "'^[Cc][Dd]$' or '^[Cc]oordinate[ _-][Dd]escent$'"]) 
239  table.add_row(["Steepest descent", "'^[Ss][Dd]$' or '^[Ss]teepest[ _-][Dd]escent$'"]) 
240  table.add_row(["Quasi-Newton BFGS", "'^[Bb][Ff][Gg][Ss]$'"]) 
241  table.add_row(["Newton", "'^[Nn]ewton$'"]) 
242  table.add_row(["Newton-CG", "'^[Nn]ewton[ _-][Cc][Gg]$' or '^[Nn][Cc][Gg]$'"]) 
243  uf.desc[-1].add_table(table.label) 
244  uf.desc[-1].add_paragraph("Unconstrained trust-region methods:") 
245  table = uf_tables.add_table(label="table: min - trust-region", caption="Minimisation algorithms -- unconstrained trust-region methods.") 
246  table.add_headings(["Minimisation algorithm", "Patterns"]) 
247  table.add_row(["Cauchy point", "'^[Cc]auchy'"]) 
248  table.add_row(["Dogleg", "'^[Dd]ogleg'"]) 
249  table.add_row(["CG-Steihaug", "'^[Cc][Gg][-_ ][Ss]teihaug' or '^[Ss]teihaug'"]) 
250  table.add_row(["Exact trust region", "'^[Ee]xact'"]) 
251  uf.desc[-1].add_table(table.label) 
252  uf.desc[-1].add_paragraph("Unconstrained conjugate gradient methods:") 
253  table = uf_tables.add_table(label="table: min - conjugate gradient", caption="Minimisation algorithms -- unconstrained conjugate gradient methods.") 
254  table.add_headings(["Minimisation algorithm", "Patterns"]) 
255  table.add_row(["Fletcher-Reeves", "'^[Ff][Rr]$' or '^[Ff]letcher[-_ ][Rr]eeves$'"]) 
256  table.add_row(["Polak-Ribiere", "'^[Pp][Rr]$' or '^[Pp]olak[-_ ][Rr]ibiere$'"]) 
257  table.add_row(["Polak-Ribiere +", "'^[Pp][Rr]\+$' or '^[Pp]olak[-_ ][Rr]ibiere\+$'"]) 
258  table.add_row(["Hestenes-Stiefel", "'^[Hh][Ss]$' or '^[Hh]estenes[-_ ][Ss]tiefel$'"]) 
259  uf.desc[-1].add_table(table.label) 
260  uf.desc[-1].add_paragraph("Miscellaneous unconstrained methods:") 
261  table = uf_tables.add_table(label="table: min - misc", caption="Minimisation algorithms -- miscellaneous unconstrained methods.") 
262  table.add_headings(["Minimisation algorithm", "Patterns"]) 
263  table.add_row(["Simplex", "'^[Ss]implex$'"]) 
264  table.add_row(["Levenberg-Marquardt", "'^[Ll][Mm]$' or '^[Ll]evenburg-[Mm]arquardt$'"]) 
265  uf.desc[-1].add_table(table.label) 
266  uf.desc[-1].add_paragraph("Global minimisation methods:") 
267  table = uf_tables.add_table(label="table: min - global", caption="Minimisation algorithms -- global minimisation methods.") 
268  table.add_headings(["Minimisation algorithm", "Patterns"]) 
269  table.add_row(["Simulated Annealing", "'^[Ss][Aa]$' or '^[Ss]imulated [Aa]nnealing$'"]) 
270  uf.desc[-1].add_table(table.label) 
271  # Minimisation options. 
272  uf.desc.append(Desc_container("Minimisation options")) 
273  uf.desc[-1].add_paragraph("The minimisation options can be given in any order.") 
274  uf.desc[-1].add_paragraph("Line search algorithms.  These are used in the line search methods and the conjugate gradient methods.  The default is the Backtracking line search.  The algorithms are:") 
275  table = uf_tables.add_table(label="table: min sub-algor - line search", caption="Minimisation sub-algorithms -- line search algorithms.") 
276  table.add_headings(["Line search algorithm", "Patterns"]) 
277  table.add_row(["Backtracking line search", "'^[Bb]ack'"]) 
278  table.add_row(["Nocedal and Wright interpolation based line search", "'^[Nn][Ww][Ii]' or '^[Nn]ocedal[ _][Ww]right[ _][Ii]nt'"]) 
279  table.add_row(["Nocedal and Wright line search for the Wolfe conditions", "'^[Nn][Ww][Ww]' or '^[Nn]ocedal[ _][Ww]right[ _][Ww]olfe'"]) 
280  table.add_row(["More and Thuente line search", "'^[Mm][Tt]' or '^[Mm]ore[ _][Tt]huente$'"]) 
281  table.add_row(["No line search", "'^[Nn]o [Ll]ine [Ss]earch$'"]) 
282  uf.desc[-1].add_table(table.label) 
283  uf.desc[-1].add_paragraph("Hessian modifications.  These are used in the Newton, Dogleg, and Exact trust region algorithms:") 
284  table = uf_tables.add_table(label="table: min sub-algor - Hessian mod", caption="Minimisation sub-algorithms -- Hessian modifications.") 
285  table.add_headings(["Hessian modification", "Patterns"]) 
286  table.add_row(["Unmodified Hessian", "'^[Nn]o [Hh]essian [Mm]od'"]) 
287  table.add_row(["Eigenvalue modification", "'^[Ee]igen'"]) 
288  table.add_row(["Cholesky with added multiple of the identity", "'^[Cc]hol'"]) 
289  table.add_row(["The Gill, Murray, and Wright modified Cholesky algorithm", "'^[Gg][Mm][Ww]$'"]) 
290  table.add_row(["The Schnabel and Eskow 1999 algorithm", "'^[Ss][Ee]99'"]) 
291  uf.desc[-1].add_table(table.label) 
292  uf.desc[-1].add_paragraph("Hessian type, these are used in a few of the trust region methods including the Dogleg and Exact trust region algorithms.  In these cases, when the Hessian type is set to Newton, a Hessian modification can also be supplied as above.  The default Hessian type is Newton, and the default Hessian modification when Newton is selected is the GMW algorithm:") 
293  table = uf_tables.add_table(label="table: min sub-algor - Hessian type", caption="Minimisation sub-algorithms -- Hessian type.") 
294  table.add_headings(["Hessian type", "Patterns"]) 
295  table.add_row(["Quasi-Newton BFGS", "'^[Bb][Ff][Gg][Ss]$'"]) 
296  table.add_row(["Newton", "'^[Nn]ewton$'"]) 
297  uf.desc[-1].add_table(table.label) 
298  uf.desc[-1].add_paragraph("For Newton minimisation, the default line search algorithm is the More and Thuente line search, while the default Hessian modification is the GMW algorithm.") 
299  # Prompt examples. 
300  uf.desc.append(Desc_container("Prompt examples")) 
301  uf.desc[-1].add_paragraph("To apply Newton minimisation together with the GMW81 Hessian modification algorithm, the More and Thuente line search algorithm, a function tolerance of 1e-25, no gradient tolerance, a maximum of 10,000,000 iterations, constraints turned on to limit parameter values, and have normal printout, type any combination of:") 
302  uf.desc[-1].add_prompt("relax> minimise.execute('newton')") 
303  uf.desc[-1].add_prompt("relax> minimise.execute('Newton')") 
304  uf.desc[-1].add_prompt("relax> minimise.execute('newton', 'gmw')") 
305  uf.desc[-1].add_prompt("relax> minimise.execute('newton', 'mt')") 
306  uf.desc[-1].add_prompt("relax> minimise.execute('newton', 'gmw', 'mt')") 
307  uf.desc[-1].add_prompt("relax> minimise.execute('newton', 'mt', 'gmw')") 
308  uf.desc[-1].add_prompt("relax> minimise.execute('newton', func_tol=1e-25)") 
309  uf.desc[-1].add_prompt("relax> minimise.execute('newton', func_tol=1e-25, grad_tol=None)") 
310  uf.desc[-1].add_prompt("relax> minimise.execute('newton', max_iter=1e7)") 
311  uf.desc[-1].add_prompt("relax> minimise.execute('newton', constraints=True, max_iter=1e7)") 
312  uf.desc[-1].add_prompt("relax> minimise.execute('newton', verbosity=1)") 
313  uf.desc[-1].add_paragraph("To use constrained Simplex minimisation with a maximum of 5000 iterations, type:") 
314  uf.desc[-1].add_prompt("relax> minimise.execute('simplex', constraints=True, max_iter=5000)") 
315  uf.backend = minimise.minimise 
316  uf.menu_text = "&execute" 
317  uf.gui_icon = "relax.rosenbrock" 
318  uf.wizard_height_desc = 300 
319  uf.wizard_size = (1000, 750) 
320  uf.wizard_image = WIZARD_IMAGE_PATH + 'minimise.png' 
321   
322   
323  # The minimise.grid_search user function. 
324  uf = uf_info.add_uf('minimise.grid_search') 
325  uf.title = "Perform a grid search to find an initial non-biased parameter set for optimisation." 
326  uf.title_short = "Grid search optimisation." 
327  uf.display = True 
328  uf.add_keyarg( 
329      name = "lower", 
330      basic_types = ["number"], 
331      container_types = ["list"], 
332      dim = (None,), 
333      desc_short = "lower bounds", 
334      desc = "An array of the lower bound parameter values for the grid search.  The length of the array should be equal to the number of parameters in the model.", 
335      can_be_none = True 
336  ) 
337  uf.add_keyarg( 
338      name = "upper", 
339      basic_types = ["number"], 
340      container_types = ["list"], 
341      dim = (None,), 
342      desc_short = "upper bounds", 
343      desc = "An array of the upper bound parameter values for the grid search.  The length of the array should be equal to the number of parameters in the model.", 
344      can_be_none = True 
345  ) 
346  uf.add_keyarg( 
347      name = "inc", 
348      default = 21, 
349      basic_types = ["int"], 
350      container_types = ["list"], 
351      dim = [(), (None,)], 
352      desc_short = "incrementation value", 
353      desc = "The number of increments to search over.  If a single integer is given then the number of increments will be equal in all dimensions.  Different numbers of increments in each direction can be set if 'inc' is set to an array of integers of length equal to the number of parameters.", 
354      none_elements = True 
355  ) 
356  uf.add_keyarg( 
357      name = "verbosity", 
358      default = 1, 
359      basic_types = ["int"], 
360      desc_short = "verbosity level", 
361      desc = "The amount of information to print to screen.  Zero corresponds to minimal output while higher values increase the amount of output.  The default value is 1." 
362  ) 
363  uf.add_keyarg( 
364      name = "constraints", 
365      default = True, 
366      basic_types = ["bool"], 
367      desc_short = "constraints flag", 
368      desc = "A boolean flag specifying whether the parameters should be constrained.  The default is to turn constraints on (constraints=True)." 
369  ) 
370  uf.add_keyarg( 
371      name = "skip_preset", 
372      default = True, 
373      basic_types = ["bool"], 
374      desc_short = "skip preset parameter flag", 
375      desc = "This argument, when True, allows any parameter which already has a value set to be skipped in the grid search.  This value will be overridden and turned off when a zooming grid search is active." 
376  ) 
377  # Description. 
378  uf.desc.append(Desc_container()) 
379  uf.desc[-1].add_paragraph("The optimisation of a mathematical model normally consists of two parts - a coarse grid search across the parameter space to find an initial set of parameter values followed by the use of a high precision optimisation algorithm to exactly find the local or global solution.  The grid search is an essential tool as it allows a non-biased initial optimisation position to be found.  It avoids the statistical bias and preconditioning introduced by using a self chosen initial parameter set.  The high computational cost of the grid search is almost always favourable to the statistical bias of a user defined starting position.") 
380  uf.desc[-1].add_paragraph("The region of the parameter space that the grid search covers is defined by the lower and upper grid bounds.  These will generally default to the entire parameter space except for when the parameter is non-bounded, for example a 3D position in the PDB space.  This user function will print out the grid bounds used and, if the default bounds are deemed to be insufficient, then the lower, upper or both bounds can supplied.  This only works if all active models have the same parameters.  The coarseness or fineness of the grid is defined by the number of increments to search across between the bounds.  For an alternative to using large numbers of increments, see the zooming grid search.") 
381  uf.desc[-1].add_paragraph("It is possible to decrease the dimensionality of the grid search, and hence drop the computational cost by orders of magnitude, if certain parameter values are know a priori.  For example if the values are determined via a different experiment.  Such parameters can be set with the value setting user function.  Then, when the skip preset flag is set, these parameters will be skipped in the grid search.  This feature should not be abused and statistical bias should be avoided at all cost.") 
382  uf.desc[-1].add_paragraph("The parameter skipping logic is as follows.  Firstly setting the increments argument to a list with None elements causes the corresponding parameters to be skipped in the grid search, or an error to be raised if no preset parameter is present.  This overrides all other settings.  Secondly the preset skipping flag only allows parameters to be skipped if the zooming grid search is non-active and a value is preset.") 
383  uf.backend = minimise.grid_search 
384  uf.menu_text = "&grid_search" 
385  uf.gui_icon = "relax.grid_search" 
386  uf.wizard_height_desc = 370 
387  uf.wizard_size = (1000, 700) 
388  uf.wizard_image = WIZARD_IMAGE_PATH + 'minimise.png' 
389   
390   
391  # The minimise.grid_zoom user function. 
392  uf = uf_info.add_uf('minimise.grid_zoom') 
393  uf.title = "Activate the zooming grid search by setting the zoom level." 
394  uf.title_short = "Zooming grid search activation." 
395  uf.add_keyarg( 
396      name = "level", 
397      default = 0, 
398      basic_types = ["number"], 
399      desc_short = "zoom level", 
400      desc = "The zooming grid search level.  This can be any number, positive or negative." 
401  ) 
402  # Description. 
403  uf.desc.append(Desc_container()) 
404  uf.desc[-1].add_paragraph("The optimisation of a mathematical model normally consists of two parts - a coarse grid search to find an initial set of parameter values followed by the use of a high precision optimisation algorithm to exactly find the local or global solution.  But in certain situations, for example where a parallelised grid search is advantageous, a finer grid may be desired.  The zooming grid search provides a more efficient alternative to simply increasing the number of increments used in the initial grid search.  Note that in most situations, standard optimisation algorithms will be by far computationally less expensive.") 
405  uf.desc[-1].add_paragraph("The zooming grid search can be activated via this user function.  After setting the desired zoom level, the original grid search user function should be called again.  The zoom level is used to decrease the total area of the grid search.  The grid width for each dimension of the parameter space will be divided by 2**zoom_level.  So a level of 1 will halve all dimensions, a level of 2 will quarter the widths, a level of 3 will be an eighth of the widths, etc.") 
406  uf.desc[-1].add_paragraph("The zooming algorithm proceeds as follows.  The new zoomed grid will be centred at the current parameter values.  However if the new grid is outside of the bounds of the original grid, the entire grid will be translated so that it lies entirely within the original bounds.  This is to avoid grid points lying within undefined regions of the space.  An exception is when the zoom factor is negative, hence the new grid will be larger than the original.") 
407  uf.desc[-1].add_paragraph("An example of using the zooming grid search is to first perform a standard initial grid search, then set the zoom level to 1 and perform a second grid search.  Continue for zoom levels 2, 3, etc. until the desired fineness is obtained.  Note that convergence is not guaranteed - as the zoom level is increased to infinity, the parameter values do not necessarily converge to the local minimum.  Therefore performing standard optimisation is recommended after completing a zooming grid search. ") 
408  uf.backend = minimise.grid_zoom 
409  uf.menu_text = "&grid_zoom" 
410  uf.gui_icon = "oxygen.actions.zoom-in" 
411  uf.wizard_height_desc = 500 
412  uf.wizard_size = (1000, 700) 
413  uf.wizard_image = WIZARD_IMAGE_PATH + 'minimise.png' 
414