def assemble_scaling_matrix(scaling=True): """Create and return the per-model scaling matrices. @keyword scaling: If True, diagonal scaling is enabled during optimisation to allow the problem to be better conditioned. @type scaling: bool @return: The list of diagonal and square scaling matrices. @rtype: list of numpy rank-2, float64 array or list of None """ # The specific analysis API object and parameter object. api = return_api() param_object = return_parameter_object() # Initialise. scaling_matrix = [] # Loop over the models. for model_info in api.model_loop(): # No diagonal scaling. if not scaling: scaling_matrix.append(None) continue # Get the parameter names. names = api.get_param_names(model_info) # No parameters for this model. if names == None or len(names) == 0: scaling_matrix.append(None) continue # The parameter number. n = len(names) # Initialise. scaling_matrix.append(identity(n, float64)) i = 0 # Update the diagonal with the parameter specific scaling factor. for i in range(n): scaling_matrix[-1][i, i] = param_object.scaling(names[i], model_info=model_info) # Return the matrix. return scaling_matrix
def grid_setup(lower=None, upper=None, inc=None, verbosity=1, skip_preset=True): """Determine the per-model grid bounds, allowing for the zooming grid search. @keyword lower: The user supplied lower bounds of the grid search which must be equal to the number of parameters in the model. @type lower: list of numbers @keyword upper: The user supplied upper bounds of the grid search which must be equal to the number of parameters in the model. @type upper: list of numbers @keyword inc: The user supplied grid search increments. @type inc: int or list of int @keyword verbosity: The amount of information to print. The higher the value, the greater the verbosity. @type verbosity: int @keyword skip_preset: This argument, when True, allows any parameter which already has a value set to be skipped in the grid search. @type skip_preset: bool @return: The per-model grid upper and lower bounds. The first dimension of each structure corresponds to the model, the second the model parameters. @rtype: tuple of lists of lists of float, lists of lists of float, list of lists of int """ # The specific analysis API object and parameter object. api = return_api() param_object = return_parameter_object() # Initialise. model_lower = [] model_upper = [] model_inc = [] # Loop over the models. for model_info in api.model_loop(): # Get the parameter names and current values. names = api.get_param_names(model_info) values = api.get_param_values(model_info) # No parameters for this model. if names == None or len(names) == 0: model_lower.append([]) model_upper.append([]) model_inc.append([]) continue # The parameter number. n = len(names) # Make sure that the length of the parameter array is > 0. if n == 0: raise RelaxError( "Cannot run a grid search on a model with zero parameters.") # Check that the user supplied bound lengths are ok. if lower != None and len(lower) != n: raise RelaxLenError('lower bounds', n) if upper != None and len(upper) != n: raise RelaxLenError('upper bounds', n) # Check the user supplied increments. if isinstance(inc, list) and len(inc) != n: raise RelaxLenError('increment', n) if isinstance(inc, list): for i in range(n): if not (isinstance(inc[i], int) or inc[i] == None): raise RelaxIntListIntError('increment', inc) elif not isinstance(inc, int): raise RelaxIntListIntError('increment', inc) # Convert to the model increment list. if isinstance(inc, int): model_inc.append([inc] * n) else: model_inc.append(inc) # Print out the model title. api.print_model_title(prefix="Grid search setup: ", model_info=model_info) # The grid zoom level. zoom = 0 if hasattr(cdp, 'grid_zoom_level'): zoom = cdp.grid_zoom_level zoom_factor = 1.0 / 2.0**zoom if zoom > 0: print( "Zooming grid level of %s, scaling the grid size by a factor of %s.\n" % (zoom, zoom_factor)) # Append empty lists for the bounds to be built up. model_lower.append([]) model_upper.append([]) # Loop over the parameters. data = [] for i in range(n): # A comment for user feedback. comment = 'Default bounds' if lower != None and upper != None: comment = 'User supplied lower and upper bound' elif lower != None: comment = 'User supplied lower bound' elif upper != None: comment = 'User supplied upper bound' # Alias the number of increments for this parameter. incs = model_inc[-1][i] # Error checking for increment values of None. if incs == None and values[i] in [None, {}, []]: raise RelaxError( "The parameter '%s' has no preset value, therefore a grid increment of None is not valid." % names[i]) # The lower bound for this parameter. if lower != None: lower_i = lower[i] else: lower_i = param_object.grid_lower(names[i], incs=incs, model_info=model_info) # The upper bound for this parameter. if upper != None: upper_i = upper[i] else: upper_i = param_object.grid_upper(names[i], incs=incs, model_info=model_info) # The skipping logic. skip = False if skip_preset: # Override the flag if the zoom is on. if zoom: skip = False # No preset value. elif values[i] in [None, {}, []]: skip = False # The preset value is a NaN value due to numpy conversions of None. elif isNaN(values[i]): skip = False # Ok, now the parameter can be skipped. else: skip = True # Override the skip flag if the incs value is None. if incs == None: skip = True # Skip preset values. if skip: lower_i = values[i] upper_i = values[i] model_inc[-1][i] = incs = 1 comment = 'Preset value' # Zooming grid. elif zoom: # The full size and scaled size. size = upper_i - lower_i zoom_size = size * zoom_factor half_size = zoom_size / 2.0 comment = 'Zoom grid width of %s %s' % ( zoom_size, param_object.units(names[i])) # The new size around the current value. lower_zoom = values[i] - half_size upper_zoom = values[i] + half_size # Outside of the original lower bound, so shift the grid to fit. if zoom > 0 and lower_zoom < lower_i: # The amount to shift by. shift = lower_i - lower_zoom # Set the new bounds. upper_i = upper_zoom + shift # Outside of the original upper bound, so shift the grid to fit. elif zoom > 0 and upper_zoom > upper_i: # The amount to shift by. shift = upper_i - upper_zoom # Set the new bounds. lower_i = lower_zoom + shift # Inside the original bounds. else: lower_i = lower_zoom upper_i = upper_zoom # Add to the data list for printing out. data.append([ names[i], "%15s" % lower_i, "%15s" % upper_i, "%15s" % incs, comment ]) # Scale the bounds. scaling = param_object.scaling(names[i], model_info=model_info) lower_i /= scaling upper_i /= scaling # Append. model_lower[-1].append(lower_i) model_upper[-1].append(upper_i) # Printout. if verbosity: write_data(out=sys.stdout, headings=[ "Parameter", "Lower bound", "Upper bound", "Increments", "Comment" ], data=data) sys.stdout.write('\n') # Return the bounds. return model_lower, model_upper, model_inc
def grid_setup(lower=None, upper=None, inc=None, verbosity=1, skip_preset=True): """Determine the per-model grid bounds, allowing for the zooming grid search. @keyword lower: The user supplied lower bounds of the grid search which must be equal to the number of parameters in the model. @type lower: list of numbers @keyword upper: The user supplied upper bounds of the grid search which must be equal to the number of parameters in the model. @type upper: list of numbers @keyword inc: The user supplied grid search increments. @type inc: int or list of int @keyword verbosity: The amount of information to print. The higher the value, the greater the verbosity. @type verbosity: int @keyword skip_preset: This argument, when True, allows any parameter which already has a value set to be skipped in the grid search. @type skip_preset: bool @return: The per-model grid upper and lower bounds. The first dimension of each structure corresponds to the model, the second the model parameters. @rtype: tuple of lists of lists of float, lists of lists of float, list of lists of int """ # The specific analysis API object and parameter object. api = return_api() param_object = return_parameter_object() # Initialise. model_lower = [] model_upper = [] model_inc = [] # Loop over the models. for model_info in api.model_loop(): # Get the parameter names and current values. names = api.get_param_names(model_info) values = api.get_param_values(model_info) # No parameters for this model. if names == None or len(names) == 0: model_lower.append([]) model_upper.append([]) model_inc.append([]) continue # The parameter number. n = len(names) # Make sure that the length of the parameter array is > 0. if n == 0: raise RelaxError("Cannot run a grid search on a model with zero parameters.") # Check that the user supplied bound lengths are ok. if lower != None and len(lower) != n: raise RelaxLenError('lower bounds', n) if upper != None and len(upper) != n: raise RelaxLenError('upper bounds', n) # Check the user supplied increments. if isinstance(inc, list) and len(inc) != n: raise RelaxLenError('increment', n) if isinstance(inc, list): for i in range(n): if not (isinstance(inc[i], int) or inc[i] == None): raise RelaxIntListIntError('increment', inc) elif not isinstance(inc, int): raise RelaxIntListIntError('increment', inc) # Convert to the model increment list. if isinstance(inc, int): model_inc.append([inc]*n) else: model_inc.append(inc) # Print out the model title. api.print_model_title(prefix="Grid search setup: ", model_info=model_info) # The grid zoom level. zoom = 0 if hasattr(cdp, 'grid_zoom_level'): zoom = cdp.grid_zoom_level zoom_factor = 1.0 / 2.0**zoom if zoom > 0: print("Zooming grid level of %s, scaling the grid size by a factor of %s.\n" % (zoom, zoom_factor)) # Append empty lists for the bounds to be built up. model_lower.append([]) model_upper.append([]) # Loop over the parameters. data = [] for i in range(n): # A comment for user feedback. comment = 'Default bounds' if lower != None and upper != None: comment = 'User supplied lower and upper bound' elif lower != None: comment = 'User supplied lower bound' elif upper != None: comment = 'User supplied upper bound' # Alias the number of increments for this parameter. incs = model_inc[-1][i] # Error checking for increment values of None. if incs == None and values[i] in [None, {}, []]: raise RelaxError("The parameter '%s' has no preset value, therefore a grid increment of None is not valid." % names[i]) # The lower bound for this parameter. if lower != None: lower_i = lower[i] else: lower_i = param_object.grid_lower(names[i], incs=incs, model_info=model_info) # The upper bound for this parameter. if upper != None: upper_i = upper[i] else: upper_i = param_object.grid_upper(names[i], incs=incs, model_info=model_info) # The skipping logic. skip = False if skip_preset: # Override the flag if the zoom is on. if zoom: skip = False # No preset value. elif values[i] in [None, {}, []]: skip = False # The preset value is a NaN value due to numpy conversions of None. elif isNaN(values[i]): skip = False # Ok, now the parameter can be skipped. else: skip = True # Override the skip flag if the incs value is None. if incs == None: skip = True # Skip preset values. if skip: lower_i = values[i] upper_i = values[i] model_inc[-1][i] = incs = 1 comment = 'Preset value' # Zooming grid. elif zoom: # The full size and scaled size. size = upper_i - lower_i zoom_size = size * zoom_factor half_size = zoom_size / 2.0 comment = 'Zoom grid width of %s %s' % (zoom_size, param_object.units(names[i])) # The new size around the current value. lower_zoom = values[i] - half_size upper_zoom = values[i] + half_size # Outside of the original lower bound, so shift the grid to fit. if zoom > 0 and lower_zoom < lower_i: # The amount to shift by. shift = lower_i - lower_zoom # Set the new bounds. upper_i = upper_zoom + shift # Outside of the original upper bound, so shift the grid to fit. elif zoom > 0 and upper_zoom > upper_i: # The amount to shift by. shift = upper_i - upper_zoom # Set the new bounds. lower_i = lower_zoom + shift # Inside the original bounds. else: lower_i = lower_zoom upper_i = upper_zoom # Add to the data list for printing out. data.append([names[i], "%15s" % lower_i, "%15s" % upper_i, "%15s" % incs, comment]) # Scale the bounds. scaling = param_object.scaling(names[i], model_info=model_info) lower_i /= scaling upper_i /= scaling # Append. model_lower[-1].append(lower_i) model_upper[-1].append(upper_i) # Printout. if verbosity: write_data(out=sys.stdout, headings=["Parameter", "Lower bound", "Upper bound", "Increments", "Comment"], data=data) sys.stdout.write('\n') # Return the bounds. return model_lower, model_upper, model_inc