def minimizeIteratively(function, *parameters): """Choose parameters to minimize 'function'. This function is similar to 'minimize', except that it proceeds by minimizing the parameters one at a time instead of simultaneously.""" if isinstance(function, str): function = hep.expr.parse(function) if not callable(function): raise TypeError, \ "'function' must be callable or an expression string" parameters = normalizeParameters(parameters) num_parameters = len(parameters) for count in range(4): indices = range(num_parameters) optimal_values = num_parameters * [ None ] for index in indices: parameter_name = parameters[index][0] min_parms = [ (name, val, None, (0, 0)) for (name, val, s, (l, h)) in parameters[: index] ] \ + [ parameters[index], ] \ + [ (name, val, None, (0, 0)) for (name, val, s, (l, h)) in parameters[index + 1: ] ] result = ext.minuit_minimize(function, min_parms, verbose) # print ' %s = %f' \ # % (parameter_name, result.values[parameter_name]) optimal_values[index] = result.values[parameter_name] sys.stdout.flush() for index in range(num_parameters): name, value, step, (lo, hi) = parameters[index] value = optimal_values[index] parameters[index] = (name, value, step, (lo, hi)) # print 'figure of merit = %f' % result.minimum # print return parameters
def minimize(function, parameters, verbose=False, minos=False, negate=False): """Choose parameters to minimize 'function'. Using Minuit, find values of named parameters that minimize the value of 'function', which may be any callable (including an 'Expression' object). Note that fixed parameters are *not* registered in Minuit as (fixed) parameters; Minuit in fact does not know anything about them. They are still passed to 'function' though. This permits arbitrarily many non-floating parameters to be used without exceeding Minuit's limit of 100 parameters. 'function' -- A callable object. It will be called with keyword arguments (only), whose names are specified in 'parameters'. All required arguments must be satisfied from 'parameters'. 'parameters' -- One or more parameters to choose. Each may be either a string name of the parameter, or a tuple '(name, initial_value, step_size, low, high)'. The second and subsequent elements in the tuple may be omitted. 'initial_value' -- The starting value for the parameter. If omitted, the default is zero (which may not be appropriate, for some functions). 'step_size' -- The starting step size. If omitted or 'None', the parameter is fixed as a constant. 'low', 'high' -- Constraints on the parameter value; if they are omitted (or both zero), the parameter is unconstrained. 'verbose' -- If true, print verbose output. 'minos' -- If true, use the MINOS algorithm to compute a better covariance matrix. 'negate' -- If true, minimizes the value of '-function'. returns -- A 'Result' instance.""" if isinstance(function, str): function = hep.expr.parse(function) if not callable(function): raise TypeError, \ "'function' must be callable or an expression string" parameters = normalizeParameters(parameters) # Do the fit. start_time = time.time() result = ext.minuit_minimize( function, parameters, verbose, minos, negate) end_time = time.time() # Store the parameter settings. result.parameters = dict([ (p[0], p[1 :]) for p in parameters ]) # Store the elapsed time. result.elapsed_time = end_time - start_time # All done. return result
def maximumLikelihoodFit(likelihood, parameters, samples, normalization_range=None, extended_fn=None, verbose=False, minos=False): """Perform an unbinned maximum likelihood fit. Fit the 'parameters' of a 'likelihood' function to maximize the likelihood of 'samples'. If 'extended_fn' is provided, performs an extended maximum likelihood fit, where 'extended_fn' is the scale function for 'likelihood'. If 'extended_fn' is not provided, performs an ordinary maximum likelihood fit. 'likelihood' -- The likelihood function or expression. 'parameters' -- A sequence of parameters. Each is of the form '(name, initial_value, step_size, lower_bound, upper_bound)', where everything after the 'name' may be omitted. 'samples' -- An iterable of samples. Each item is a mapping of sample variable name to value. An iterator must not be used here; the function needs to iterate over the samples multiple times. 'normalization_range' -- The likelihood function in a maximum likelihood fit must be normalized over the sample space. If 'likelihood' is already normalized, this parameter may be 'None'. Otherwise, it is a sequence of integration ranges of the form '(var_name, lo, hi)', over which the likelihood function is numerically integrated for each choice of parameters. The 'lo' and 'hi' values may be constants or expressions involving the parameters. 'extended_fn' -- If provided, the function to use in an extended maximum likelihood fit. returns -- A minimization 'Result' object.""" # Convert the likelihood function to an expression object. likelihood = hep.expr.asExpression(likelihood) # Set the types of the symbols for the sample variables and # parameters to 'float'. This will produce better compiled # expressions. likelihood = hep.expr.op.setTypesFixed(likelihood, None, float) # Clean up the parameters specification. parameters = normalizeParameters(parameters) if normalization_range is not None: # Convert the normalization range bounds to expression objects. normalization_range = [ (var, hep.expr.asExpression(lo), hep.expr.asExpression(hi)) for (var, lo, hi) in normalization_range ] if extended_fn is not None: # Convert the extended function to an expression object. extended_fn = hep.expr.asExpression(extended_fn) # As with the likelihood function, all symbol types are floats. extended_fn = hep.expr.op.setTypesFixed(extended_fn, None, float) # Use its evaluate function. extended_fn = extended_fn.evaluate # Get busy. result = ext.minuit_maximumLikelihoodFit( likelihood, parameters, samples, normalization_range, extended_fn, verbose, minos) result.parameters = dict([ (p[0], p[1 :]) for p in parameters ]) # Construct the resulting likelihood function. fit_likelihood = hep.expr.substitute(likelihood, **result.values) # Normalize it, if necessary. if normalization_range is not None: from hep.cernlib import integrate integral = integrate(fit_likelihood, *[ (name, lo(**result.values), hi(**result.values)) for (name, lo, hi) in normalization_range ]) fit_likelihood = hep.expr.Multiply( fit_likelihood, hep.expr.Constant(1 / integral)) result.likelihood = fit_likelihood return result