Example #1
0
def plot_asimov_line(llh_dict, tkey, max_yval, **kwargs):
    """
    llh_dict  - dictionary of llh data
    tkey      - key of the true hierarchy (from asimov or pseudo data set)
    max_yval  - maximum yvalue for asimov line.
    """

    validate_key(tkey)

    asimov_data = llh_dict[tkey]['asimov_data']
    asimov_data_null = llh_dict[tkey]['asimov_data_null']

    llh_asimov = get_binwise_llh(asimov_data,asimov_data)
    llh_null = -llh_dict[tkey]['llh_null']['llh'][-1]

    logging.info("  >> llh_asimov: %.4f"%llh_asimov)
    logging.info("  >> llh null: %.4f"%llh_null)
    logging.info("Null hypothesis: ")
    for k,v in llh_dict[tkey]['llh_null'].items():
        logging.info("  >> %s: %f"%(k,v[-1]))

    asimov_llr = (llh_null - llh_asimov if 'true_N' in tkey
                  else llh_asimov - llh_null)
    vline = plt.vlines(
        asimov_llr, 0.1, max_yval ,colors='k',**kwargs)

    return asimov_llr
Example #2
0
def find_max_llh_bfgs(fmap, template_maker, params, bfgs_settings, save_steps=False,
                      normal_hierarchy=None, check_octant=False):
    """
    Finds the template (and free systematic params) that maximize
    likelihood that the data came from the chosen template of true
    params, using the limited memory BFGS algorithm subject to bounds
    (l_bfgs_b).

    returns a dictionary of llh data and best fit params, in the format:
      {'llh': [...],
       'param1': [...],
       'param2': [...],
       ...}
    where 'param1', 'param2', ... are the free params varied by
    optimizer, and they hold a list of all the values tested in
    optimizer algorithm, unless save_steps is False, in which case
    they are one element in length-the best fit params and best fit llh.
    """

    # Get params dict which will be optimized (free_params) and which
    # won't be (fixed_params) but are still needed for get_template()
    fixed_params = get_fixed_params(select_hierarchy(params,normal_hierarchy))
    free_params = get_free_params(select_hierarchy(params,normal_hierarchy))

    if len(free_params) == 0:
        logging.warn("NO FREE PARAMS, returning LLH")
        true_template = template_maker.get_template(get_values(fixed_params))
        channel = params['channel']['value']
        true_fmap = flatten_map(true_template,chan=channel)
        return {'llh': [-get_binwise_llh(fmap,true_fmap)]}

    init_vals = get_param_values(free_params)
    scales = get_param_scales(free_params)
    bounds = get_param_bounds(free_params)
    priors = get_param_priors(free_params)
    names  = sorted(free_params.keys())

    # Scale init-vals and bounds to work with bfgs opt:
    init_vals = np.array(init_vals)*np.array(scales)
    bounds = [bounds[i]*scales[i] for i in range(len(bounds))]

    opt_steps_dict = {key:[] for key in names}
    opt_steps_dict['llh'] = []

    const_args = (names,scales,fmap,fixed_params,template_maker,opt_steps_dict,priors)

    display_optimizer_settings(free_params, names, init_vals, bounds, priors,
                               bfgs_settings)

    best_fit_vals,llh,dict_flags = opt.fmin_l_bfgs_b(
        llh_bfgs, init_vals, args=const_args, approx_grad=True, iprint=0,
        bounds=bounds, **get_values(bfgs_settings))

    # If needed, run optimizer again, checking for second octant solution:
    if check_octant and ('theta23' in free_params.keys()):
        physics.info("Checking alternative octant solution")
        old_th23_val = free_params['theta23']['value']
        delta = np.pi - old_th23_val
        free_params['theta23']['value'] = np.pi + delta
        init_vals = get_param_values(free_params)

        const_args = (names,scales,fmap,fixed_params,template_maker,opt_steps_dict,priors)
        display_optimizer_settings(free_params, names, init_vals, bounds, priors,
                                   bfgs_settings)
        alt_fit_vals,alt_llh,alt_dict_flags = opt.fmin_l_bfgs_b(
            llh_bfgs, init_vals, args=const_args, approx_grad=True, iprint=0,
            bounds=bounds, **get_values(bfgs_settings))

        # Alternative octant solution is optimal:
        if alt_llh < llh:
            best_fit_vals = alt_fit_vals
            llh = alt_llh
            dict_flags = alt_dict_flags


    best_fit_params = { name: value for name, value in zip(names, best_fit_vals) }

    #Report best fit
    physics.info('Found best LLH = %.2f in %d calls at:'
        %(llh,dict_flags['funcalls']))
    for name, val in best_fit_params.items():
        physics.info('  %20s = %6.4f'%(name,val))

    #Report any warnings if there are
    lvl = logging.WARN if (dict_flags['warnflag'] != 0) else logging.DEBUG
    for name, val in dict_flags.items():
        physics.log(lvl," %s : %s"%(name,val))

    if not save_steps:
        # Do not store the extra history of opt steps:
        for key in opt_steps_dict.keys():
            opt_steps_dict[key] = [opt_steps_dict[key][-1]]

    return opt_steps_dict
Example #3
0
def llh_bfgs(opt_vals,*args):
    """
    Function that the bfgs algorithm tries to minimize. Essentially,
    it is a wrapper function around get_template() and
    get_binwise_llh().

    This fuction is set up this way, because the fmin_l_bfgs_b
    algorithm must take a function with two inputs: params & *args,
    where 'params' are the actual VALUES to be varied, and must
    correspond to the limits in 'bounds', and 'args' are arguments
    which are not varied and optimized, but needed by the
    get_template() function here. Thus, we pass the arguments to this
    function as follows:

    --opt_vals: [param1,param2,...,paramN] - systematics varied in the optimization.
    --args: [names,scales,fmap,fixed_params,template_maker,opt_steps_dict,priors]
      where
        names: are the dict keys corresponding to param1, param2,...
        scales: the scales to be applied before passing to get_template
          [IMPORTANT! In the optimizer, all parameters must be ~ the same order.
          Here, we keep them between 0.1,1 so the "epsilon" step size will vary
          the parameters in roughly the same precision.]
        fmap: pseudo data flattened map
        fixed_params: dictionary of other paramters needed by the get_template()
          function
        template_maker: template maker object
        opt_steps_dict: dictionary recording information regarding the steps taken
          for each trial of the optimization process.
        priors: gaussian priors corresponding to opt_vals list.
          Format: [(prior1,best1),(prior2,best2),...,(priorN,bestN)]
    """


    names,scales,fmap,fixed_params,template_maker,opt_steps_dict,priors = args

    # free parameters being "optimized" by minimizer re-scaled to their true values.
    unscaled_opt_vals = [opt_vals[i]/scales[i] for i in xrange(len(opt_vals))]

    unscaled_free_params = { names[i]: val for i,val in enumerate(unscaled_opt_vals) }
    template_params = dict(unscaled_free_params.items() + get_values(fixed_params).items())

    # Now get true template, and compute LLH
    with Timer() as t:
        if template_params['theta23'] == 0.0:
            logging.info("Zero theta23, so generating no oscillations template...")
            true_template = template_maker.get_template_no_osc(template_params)
        else:
            true_template = template_maker.get_template(template_params)
    profile.info("==> elapsed time for template maker: %s sec"%t.secs)
    true_fmap = flatten_map(true_template,chan=template_params['channel'])

    # NOTE: The minus sign is present on both of these next two lines
    # to reflect the fact that the optimizer finds a minimum rather
    # than maximum.
    llh = -get_binwise_llh(fmap,true_fmap)
    llh -= sum([ get_prior_llh(opt_val,sigma,value)
                 for (opt_val,(sigma,value)) in zip(unscaled_opt_vals,priors)])

    # Save all optimizer-tested values to opt_steps_dict, to see
    # optimizer history later
    for key in names:
        opt_steps_dict[key].append(template_params[key])
    opt_steps_dict['llh'].append(llh)

    physics.debug("LLH is %.2f at: "%llh)
    for name, val in zip(names, opt_vals):
        physics.debug(" %20s = %6.4f" %(name,val))

    return llh
Example #4
0
def find_max_llh_bfgs(fmap,template_maker,params,bfgs_settings,save_steps=False,
                      normal_hierarchy=None):
    '''
    Finds the template (and free systematic params) that maximize
    likelihood that the data came from the chosen template of true
    params, using the limited memory BFGS algorithm subject to bounds
    (l_bfgs_b).

    returns a dictionary of llh data and best fit params, in the format:
      {'llh': [...],
       'param1': [...],
       'param2': [...],
       ...}
    where 'param1', 'param2', ... are the free params varied by
    optimizer, and they hold a list of all the values tested in
    optimizer algorithm, unless save_steps is False, in which case
    they are one element in length-the best fit params and best fit llh.
    '''

    # Get params dict which will be optimized (free_params) and which
    # won't be (fixed_params) but are still needed for get_template()
    fixed_params = get_fixed_params(select_hierarchy(params,normal_hierarchy))
    free_params = get_free_params(select_hierarchy(params,normal_hierarchy))

    if len(free_params) == 0:
        logging.warn("NO FREE PARAMS, returning LLH")
        true_template = template_maker.get_template(get_values(fixed_params))
        channel = params['channel']['value']
        true_fmap = flatten_map(true_template,chan=channel)
        return {'llh': [-get_binwise_llh(fmap,true_fmap)]}

    init_vals = get_param_values(free_params)
    scales = get_param_scales(free_params)
    bounds = get_param_bounds(free_params)
    priors = get_param_priors(free_params)
    names  = sorted(free_params.keys())

    # Scale init-vals and bounds to work with bfgs opt:
    init_vals = np.array(init_vals)*np.array(scales)
    bounds = [bounds[i]*scales[i] for i in range(len(bounds))]

    opt_steps_dict = {key:[] for key in names}
    opt_steps_dict['llh'] = []

    const_args = (names,scales,fmap,fixed_params,template_maker,opt_steps_dict,priors)

    physics.info('%d parameters to be optimized'%len(free_params))
    for name,init,(down,up),(prior, best) in zip(names, init_vals, bounds, priors):
        physics.info(('%20s : init = %6.4f, bounds = [%6.4f,%6.4f], '
                     'best = %6.4f, prior = '+
                     ('%6.4f' if prior else "%s"))%
                     (name, init, up, down, best, prior))

    physics.debug("Optimizer settings:")
    for key,item in bfgs_settings.items():
        physics.debug("  %s -> `%s` = %.2e"%(item['desc'],key,item['value']))

    best_fit_vals,llh,dict_flags = opt.fmin_l_bfgs_b(llh_bfgs,
                                                     init_vals,
                                                     args=const_args,
                                                     approx_grad=True,
                                                     iprint=0,
                                                     bounds=bounds,
                                                     **get_values(bfgs_settings))

    best_fit_params = { name: value for name, value in zip(names, best_fit_vals) }

    #Report best fit
    physics.info('Found best LLH = %.2f in %d calls at:'
        %(llh,dict_flags['funcalls']))
    for name, val in best_fit_params.items():
        physics.info('  %20s = %6.4f'%(name,val))

    #Report any warnings if there are
    lvl = logging.WARN if (dict_flags['warnflag'] != 0) else logging.DEBUG
    for name, val in dict_flags.items():
        physics.log(lvl," %s : %s"%(name,val))

    if not save_steps:
        # Do not store the extra history of opt steps:
        for key in opt_steps_dict.keys():
            opt_steps_dict[key] = [opt_steps_dict[key][-1]]

    return opt_steps_dict
Example #5
0
def find_max_grid(fmap,
                  template_maker,
                  params,
                  grid_settings,
                  save_steps=True,
                  normal_hierarchy=True):
    '''
    Finds the template (and free systematic params) that maximize
    likelihood that the data came from the chosen template of true
    params, using a brute force grid scan over the whole parameter space.

    returns a dictionary of llh data and best fit params, in the format:
      {'llh': [...],
       'param1': [...],
       'param2': [...],
       ...}
    where 'param1', 'param2', ... are the free params that are varied in the
    scan. If save_steps is False, all lists only contain the best-fit parameters
    and llh values.
    '''

    #print "NOW INSIDE find_max_grid:"
    #print "After fixing to their true values, params dict is now: "
    #for key in params.keys():
    #    try: print "  >>param: %s value: %s"%(key,str(params[key]['best']))
    #    except: continue

    # Get params dict which will be optimized (free_params) and which
    # won't be (fixed_params) but are still needed for get_template()
    fixed_params = get_fixed_params(select_hierarchy(params, normal_hierarchy))
    free_params = get_free_params(select_hierarchy(params, normal_hierarchy))

    # Obtain just the priors
    priors = get_param_priors(free_params)

    # Calculate steps [(prior,value),...] for all free parameters
    calc_steps(free_params, grid_settings['steps'])

    # Build a list from all parameters that holds a list of (name, step) tuples
    steplist = [[(name, step) for step in param['steps']]
                for name, param in sorted(free_params.items())]

    # Prepare to store all the steps
    steps = {key: [] for key in free_params.keys()}
    steps['llh'] = []

    # Iterate over the cartesian product
    for pos in product(*steplist):

        # Get a dict with all parameter values at this position
        # including the fixed parameters
        template_params = dict(list(pos) + get_values(fixed_params).items())

        #print "   >> NOW IN LOOP: "
        #for key in template_params.keys():
        #    try: print "  >>param: %s value: %s"%(key,str(template_params[key]['value']))
        #    except: continue

        # Now get true template
        tprofile.info('start template calculation')
        true_template = template_maker.get_template(template_params)
        tprofile.info('stop template calculation')
        true_fmap = flatten_map(true_template)

        # and calculate the likelihood
        llh = -get_binwise_llh(fmap, true_fmap)

        # get sorted vals to match with priors
        vals = [v for k, v in sorted(pos)]
        llh -= sum([prior.llh(val) for val, prior in zip(vals, priors)])

        # Save all values to steps and report
        steps['llh'].append(llh)
        physics.debug("LLH is %.2f at: " % llh)
        for key, val in pos:
            steps[key].append(val)
            physics.debug(" %20s = %6.4f" % (key, val))

    # Find best fit value
    maxllh = min(steps['llh'])
    maxpos = steps['llh'].index(maxllh)

    # Report best fit
    physics.info('Found best LLH = %.2f in %d calls at:' %
                 (maxllh, len(steps['llh'])))
    for name, vals in steps.items():
        physics.info('  %20s = %6.4f' % (name, vals[maxpos]))

        # only save this maximum if asked for
        if not save_steps:
            steps[name] = vals[maxpos]

    return steps
Example #6
0
def bfgs_metric(opt_vals, names, scales, fmap, fixed_params, template_maker,
                opt_steps_dict, priors, metric_name='llh'):
    """
    Function that the bfgs algorithm tries to minimize: wraps get_template()
    and get_binwise_llh() (or get_binwise_chisquare()), and returns
    the negative log likelihood (the chisquare).

    This function is set up this way because the fmin_l_bfgs_b algorithm must
    take a function with two inputs: params & *args, where 'params' are the
    actual VALUES to be varied, and must correspond to the limits in 'bounds',
    and 'args' are arguments which are not varied and optimized, but needed by
    the get_template() function here.

    Parameters
    ----------
    opt_vals : sequence of scalars
        Systematics varied in the optimization.
        Format: [param1, param2, ... , paramN]
    names : sequence of str
        Dictionary keys corresponding to param1, param2, ...
    scales : sequence of float
        Scales to be applied before passing to get_template
        [IMPORTANT! In the optimizer, all parameters must be ~ the same order.
        Here, we keep them between 0.1,1 so the "epsilon" step size will vary
        the parameters with roughly the same precision.]
    fmap : sequence of float
        Pseudo data flattened map
    fixed_params : dict
        Other paramters needed by the get_template() function.
    template_maker : template maker object
    opt_steps_dict: dict
        Dictionary recording information regarding the steps taken for each
        trial of the optimization process.
    priors : sequence of pisa.utils.params.Prior objects
        Priors corresponding to opt_vals list.
    metric_name : string
	Returns chisquare instead of negative llh if metric_name is 'chisquare'.
	Note: this string has to be present as a key in opt_steps_dict

    Returns
    -------
    metric_val : float
        either minimum negative llh or chisquare found by BFGS minimizer

    """
    # free parameters being "optimized" by minimizer re-scaled to their true
    # values.
    unscaled_opt_vals = [opt_vals[i]/scales[i] for i in xrange(len(opt_vals))]

    unscaled_free_params = { names[i]: val for i,val in enumerate(unscaled_opt_vals) }
    template_params = dict(unscaled_free_params.items() +
                           get_values(fixed_params).items())

    # Now get true template, and compute metric
    with Timer() as t:
        if template_params['theta23'] == 0.0:
            logging.info("Zero theta23, so generating no oscillations template...")
            true_template = template_maker.get_template_no_osc(template_params)
        else:
            true_template = template_maker.get_template(template_params)

    tprofile.info("==> elapsed time for template maker: %s sec"%t.secs)
    true_fmap = flatten_map(template=true_template,
                            channel=template_params['channel'])

    # NOTE: The minus sign is present on both of these next two lines
    # because the optimizer finds a minimum rather than maximum, so we
    # have to minimize the negative of the log likelhood.
    if metric_name=='chisquare':
	metric_val = get_binwise_chisquare(fmap, true_fmap)
	metric_val += sum([prior.chi2(opt_val)
                           for (opt_val, prior) in zip(unscaled_opt_vals, priors)])
    elif metric_name=='llh':
	metric_val = -get_binwise_llh(fmap, true_fmap)
	metric_val -= sum([prior.llh(opt_val)
                           for (opt_val, prior) in zip(unscaled_opt_vals, priors)])

    #prior_list = [prior.llh(opt_val)
    #         for (opt_val, prior) in zip(unscaled_opt_vals, priors)]
    #print("  prior sum: ",sum(prior_list))
    #neg_llh -= sum(prior_list)

    # Save all optimizer-tested values to opt_steps_dict, to see
    # optimizer history later
    for key in names:
        opt_steps_dict[key].append(template_params[key])
    opt_steps_dict[metric_name].append(metric_val)

    physics.debug("%s is %.2f at: "%(metric_name, metric_val))
    for name, val in zip(names, opt_vals):
        physics.debug(" %20s = %6.4f" %(name,val))

    return metric_val
Example #7
0
def find_max_llh_bfgs(fmap,
                      template_maker,
                      params,
                      bfgs_settings,
                      save_steps=False,
                      normal_hierarchy=None,
                      check_octant=False):
    """
    Finds the template (and free systematic params) that maximize
    likelihood that the data came from the chosen template of true
    params, using the limited memory BFGS algorithm subject to bounds
    (l_bfgs_b).

    returns a dictionary of llh data and best fit params, in the format:
      {'llh': [...],
       'param1': [...],
       'param2': [...],
       ...}
    where 'param1', 'param2', ... are the free params varied by
    optimizer, and they hold a list of all the values tested in
    optimizer algorithm, unless save_steps is False, in which case
    they are one element in length-the best fit params and best fit llh.
    """

    # Get params dict which will be optimized (free_params) and which
    # won't be (fixed_params) but are still needed for get_template()
    fixed_params = get_fixed_params(select_hierarchy(params, normal_hierarchy))
    free_params = get_free_params(select_hierarchy(params, normal_hierarchy))

    if len(free_params) == 0:
        logging.warn("NO FREE PARAMS, returning LLH")
        true_template = template_maker.get_template(get_values(fixed_params))
        channel = params['channel']['value']
        true_fmap = flatten_map(true_template, chan=channel)
        return {'llh': [-get_binwise_llh(fmap, true_fmap)]}

    init_vals = get_param_values(free_params)
    scales = get_param_scales(free_params)
    bounds = get_param_bounds(free_params)
    priors = get_param_priors(free_params)
    names = sorted(free_params.keys())

    # Scale init-vals and bounds to work with bfgs opt:
    init_vals = np.array(init_vals) * np.array(scales)
    bounds = [bounds[i] * scales[i] for i in range(len(bounds))]

    opt_steps_dict = {key: [] for key in names}
    opt_steps_dict['llh'] = []

    const_args = (names, scales, fmap, fixed_params, template_maker,
                  opt_steps_dict, priors)

    display_optimizer_settings(free_params, names, init_vals, bounds, priors,
                               bfgs_settings)

    best_fit_vals, llh, dict_flags = opt.fmin_l_bfgs_b(
        llh_bfgs,
        init_vals,
        args=const_args,
        approx_grad=True,
        iprint=0,
        bounds=bounds,
        **get_values(bfgs_settings))

    # If needed, run optimizer again, checking for second octant solution:
    if check_octant and ('theta23' in free_params.keys()):
        physics.info("Checking alternative octant solution")
        old_th23_val = free_params['theta23']['value']
        delta = np.pi - old_th23_val
        free_params['theta23']['value'] = np.pi + delta
        init_vals = get_param_values(free_params)

        const_args = (names, scales, fmap, fixed_params, template_maker,
                      opt_steps_dict, priors)
        display_optimizer_settings(free_params, names, init_vals, bounds,
                                   priors, bfgs_settings)
        alt_fit_vals, alt_llh, alt_dict_flags = opt.fmin_l_bfgs_b(
            llh_bfgs,
            init_vals,
            args=const_args,
            approx_grad=True,
            iprint=0,
            bounds=bounds,
            **get_values(bfgs_settings))

        # Alternative octant solution is optimal:
        if alt_llh < llh:
            best_fit_vals = alt_fit_vals
            llh = alt_llh
            dict_flags = alt_dict_flags

    best_fit_params = {
        name: value
        for name, value in zip(names, best_fit_vals)
    }

    #Report best fit
    physics.info('Found best LLH = %.2f in %d calls at:' %
                 (llh, dict_flags['funcalls']))
    for name, val in best_fit_params.items():
        physics.info('  %20s = %6.4f' % (name, val))

    #Report any warnings if there are
    lvl = logging.WARN if (dict_flags['warnflag'] != 0) else logging.DEBUG
    for name, val in dict_flags.items():
        physics.log(lvl, " %s : %s" % (name, val))

    if not save_steps:
        # Do not store the extra history of opt steps:
        for key in opt_steps_dict.keys():
            opt_steps_dict[key] = [opt_steps_dict[key][-1]]

    return opt_steps_dict
Example #8
0
def llh_bfgs(opt_vals, *args):
    """
    Function that the bfgs algorithm tries to minimize. Essentially,
    it is a wrapper function around get_template() and
    get_binwise_llh().

    This fuction is set up this way, because the fmin_l_bfgs_b
    algorithm must take a function with two inputs: params & *args,
    where 'params' are the actual VALUES to be varied, and must
    correspond to the limits in 'bounds', and 'args' are arguments
    which are not varied and optimized, but needed by the
    get_template() function here. Thus, we pass the arguments to this
    function as follows:

    --opt_vals: [param1,param2,...,paramN] - systematics varied in the optimization.
    --args: [names,scales,fmap,fixed_params,template_maker,opt_steps_dict,priors]
      where
        names: are the dict keys corresponding to param1, param2,...
        scales: the scales to be applied before passing to get_template
          [IMPORTANT! In the optimizer, all parameters must be ~ the same order.
          Here, we keep them between 0.1,1 so the "epsilon" step size will vary
          the parameters in roughly the same precision.]
        fmap: pseudo data flattened map
        fixed_params: dictionary of other paramters needed by the get_template()
          function
        template_maker: template maker object
        opt_steps_dict: dictionary recording information regarding the steps taken
          for each trial of the optimization process.
        priors: gaussian priors corresponding to opt_vals list.
          Format: [(prior1,best1),(prior2,best2),...,(priorN,bestN)]
    """

    names, scales, fmap, fixed_params, template_maker, opt_steps_dict, priors = args

    # free parameters being "optimized" by minimizer re-scaled to their true values.
    unscaled_opt_vals = [
        opt_vals[i] / scales[i] for i in xrange(len(opt_vals))
    ]

    unscaled_free_params = {
        names[i]: val
        for i, val in enumerate(unscaled_opt_vals)
    }
    template_params = dict(unscaled_free_params.items() +
                           get_values(fixed_params).items())

    # Now get true template, and compute LLH
    with Timer() as t:
        if template_params['theta23'] == 0.0:
            logging.info(
                "Zero theta23, so generating no oscillations template...")
            true_template = template_maker.get_template_no_osc(template_params)
        else:
            true_template = template_maker.get_template(template_params)
    profile.info("==> elapsed time for template maker: %s sec" % t.secs)
    true_fmap = flatten_map(true_template, chan=template_params['channel'])

    # NOTE: The minus sign is present on both of these next two lines
    # to reflect the fact that the optimizer finds a minimum rather
    # than maximum.
    llh = -get_binwise_llh(fmap, true_fmap)
    llh -= sum([
        get_prior_llh(opt_val, sigma, value)
        for (opt_val, (sigma, value)) in zip(unscaled_opt_vals, priors)
    ])

    # Save all optimizer-tested values to opt_steps_dict, to see
    # optimizer history later
    for key in names:
        opt_steps_dict[key].append(template_params[key])
    opt_steps_dict['llh'].append(llh)

    physics.debug("LLH is %.2f at: " % llh)
    for name, val in zip(names, opt_vals):
        physics.debug(" %20s = %6.4f" % (name, val))

    return llh
Example #9
0
File: Scan.py Project: mamday/pisa
def find_max_grid(fmap,template_maker,params,grid_settings,save_steps=True,
                                                     normal_hierarchy=True):
    '''
    Finds the template (and free systematic params) that maximize
    likelihood that the data came from the chosen template of true
    params, using a brute force grid scan over the whole parameter space.

    returns a dictionary of llh data and best fit params, in the format:
      {'llh': [...],
       'param1': [...],
       'param2': [...],
       ...}
    where 'param1', 'param2', ... are the free params that are varied in the
    scan. If save_steps is False, all lists only contain the best-fit parameters
    and llh values.
    '''

    #print "NOW INSIDE find_max_grid:"
    #print "After fixing to their true values, params dict is now: "
    #for key in params.keys():
    #    try: print "  >>param: %s value: %s"%(key,str(params[key]['best']))
    #    except: continue


    # Get params dict which will be optimized (free_params) and which
    # won't be (fixed_params) but are still needed for get_template()
    fixed_params = get_fixed_params(select_hierarchy(params,normal_hierarchy))
    free_params = get_free_params(select_hierarchy(params,normal_hierarchy))

    #Obtain just the priors
    priors = get_param_priors(free_params)

    #Calculate steps for all free parameters
    calc_steps(free_params, grid_settings['steps'])

    #Build a list from all parameters that holds a list of (name, step) tuples
    steplist = [ [(name,step) for step in param['steps']] for name, param in sorted(free_params.items())]

    #Prepare to store all the steps
    steps = {key:[] for key in free_params.keys()}
    steps['llh'] = []

    #Iterate over the cartesian product
    for pos in product(*steplist):

        #Get a dict with all parameter values at this position
        #including the fixed parameters
        template_params = dict(list(pos) + get_values(fixed_params).items())

        #print "   >> NOW IN LOOP: "
        #for key in template_params.keys():
        #    try: print "  >>param: %s value: %s"%(key,str(template_params[key]['value']))
        #    except: continue

        # Now get true template
        profile.info('start template calculation')
        true_template = template_maker.get_template(template_params)
        profile.info('stop template calculation')
        true_fmap = flatten_map(true_template)

        #and calculate the likelihood
        llh = -get_binwise_llh(fmap,true_fmap)

        #get sorted vals to match with priors
        vals = [ v for k,v in sorted(pos) ]
        llh -= sum([ get_prior_llh(vals,sigma,value) for (vals,(sigma,value)) in zip(vals,priors)])

        # Save all values to steps and report
        steps['llh'].append(llh)
        physics.debug("LLH is %.2f at: "%llh)
        for key, val in pos:
            steps[key].append(val)
            physics.debug(" %20s = %6.4f" %(key, val))

    #Find best fit value
    maxllh = min(steps['llh'])
    maxpos = steps['llh'].index(maxllh)

    #Report best fit
    physics.info('Found best LLH = %.2f in %d calls at:'
                 %(maxllh,len(steps['llh'])))
    for name, vals in steps.items():
        physics.info('  %20s = %6.4f'%(name,vals[maxpos]))

        #only save this maximum if asked for
        if not save_steps:
            steps[name]=vals[maxpos]

    return steps
Example #10
0
def bfgs_metric(opt_vals,
                names,
                scales,
                fmap,
                fixed_params,
                template_maker,
                opt_steps_dict,
                priors,
                metric_name='llh'):
    """
    Function that the bfgs algorithm tries to minimize: wraps get_template()
    and get_binwise_llh() (or get_binwise_chisquare()), and returns
    the negative log likelihood (the chisquare).

    This function is set up this way because the fmin_l_bfgs_b algorithm must
    take a function with two inputs: params & *args, where 'params' are the
    actual VALUES to be varied, and must correspond to the limits in 'bounds',
    and 'args' are arguments which are not varied and optimized, but needed by
    the get_template() function here.

    Parameters
    ----------
    opt_vals : sequence of scalars
        Systematics varied in the optimization.
        Format: [param1, param2, ... , paramN]
    names : sequence of str
        Dictionary keys corresponding to param1, param2, ...
    scales : sequence of float
        Scales to be applied before passing to get_template
        [IMPORTANT! In the optimizer, all parameters must be ~ the same order.
        Here, we keep them between 0.1,1 so the "epsilon" step size will vary
        the parameters with roughly the same precision.]
    fmap : sequence of float
        Pseudo data flattened map
    fixed_params : dict
        Other paramters needed by the get_template() function.
    template_maker : template maker object
    opt_steps_dict: dict
        Dictionary recording information regarding the steps taken for each
        trial of the optimization process.
    priors : sequence of pisa.utils.params.Prior objects
        Priors corresponding to opt_vals list.
    metric_name : string
	Returns chisquare instead of negative llh if metric_name is 'chisquare'.
	Note: this string has to be present as a key in opt_steps_dict

    Returns
    -------
    metric_val : float
        either minimum negative llh or chisquare found by BFGS minimizer

    """
    # free parameters being "optimized" by minimizer re-scaled to their true
    # values.
    unscaled_opt_vals = [
        opt_vals[i] / scales[i] for i in xrange(len(opt_vals))
    ]

    unscaled_free_params = {
        names[i]: val
        for i, val in enumerate(unscaled_opt_vals)
    }
    template_params = dict(unscaled_free_params.items() +
                           get_values(fixed_params).items())

    # Now get true template, and compute metric
    with Timer() as t:
        if template_params['theta23'] == 0.0:
            logging.info(
                "Zero theta23, so generating no oscillations template...")
            true_template = template_maker.get_template_no_osc(template_params)
        else:
            true_template = template_maker.get_template(template_params)

    tprofile.info("==> elapsed time for template maker: %s sec" % t.secs)
    true_fmap = flatten_map(template=true_template,
                            channel=template_params['channel'])

    # NOTE: The minus sign is present on both of these next two lines
    # because the optimizer finds a minimum rather than maximum, so we
    # have to minimize the negative of the log likelhood.
    if metric_name == 'chisquare':
        metric_val = get_binwise_chisquare(fmap, true_fmap)
        metric_val += sum([
            prior.chi2(opt_val)
            for (opt_val, prior) in zip(unscaled_opt_vals, priors)
        ])
    elif metric_name == 'llh':
        metric_val = -get_binwise_llh(fmap, true_fmap)
        metric_val -= sum([
            prior.llh(opt_val)
            for (opt_val, prior) in zip(unscaled_opt_vals, priors)
        ])

    # Save all optimizer-tested values to opt_steps_dict, to see
    # optimizer history later
    for key in names:
        opt_steps_dict[key].append(template_params[key])
    opt_steps_dict[metric_name].append(metric_val)

    physics.debug("%s is %.2f at: " % (metric_name, metric_val))
    for name, val in zip(names, opt_vals):
        physics.debug(" %20s = %6.4f" % (name, val))

    return metric_val