def construct_despot1_cost_function(cost_func, n_images, params, start_range, constraints):
    """
    Arguments:
        cost_func --
        params -- the parameters that are free to vary for each sequence
        start_range -- 
        constraints -- 
    """
    DESPOT1_Cost_Function = MultiOptimizationHelper(cost_func, n_images, params=params, start_range=start_range)
    indices = DESPOT1_Cost_Function.parameter_indices
    # TODO name the constants
    for seq in n_images:
        # nex must be > 0.01 to avoid singular F
        DESPOT1_Cost_Function.add_affine_constraint((seq, 'nex'), 'ineq', 1.0, -0.01)
    if 'spgr' in indices and 'theta' in indices['spgr']:
        DESPOT1_Cost_Function.add_affine_constraint(('spgr', 'theta'), 'ineq', 1.0, -1./32767.)
        # theta must be < 80 for spgr
        DESPOT1_Cost_Function.add_affine_constraint(('spgr', 'theta'), 'ineq', -1.0, np.pi*80./180.)
        # sort theta ascending
        for prev, next in zip(indices['spgr']['theta'][:-1], indices['spgr']['theta'][1:]):
            DESPOT1_Cost_Function.constraints.append({
                'type': 'ineq',
                'fun': lambda x, prev=prev, next=next: x[next] - x[prev]
            })   
    # TODO: modify this to account for differences in tr between seq.
    # Fixed time constraint
    DESPOT1_Cost_Function.constraints.append({
        'type': 'eq',
        'fun': lambda x, spgr_nex_idx=indices['spgr']['nex']: sum(x[spgr_nex_idx]) - 10.
    })
    return DESPOT1_Cost_Function
def construct_diffusion_cost_function(cost_func, n_images, params, start_range, constraints):
    """
    Arguments:
        cost_func --
        params -- the parameters that are free to vary for each sequence
        start_range -- 
        constraints -- 
    """
    Cost_Function = MultiOptimizationHelper(cost_func, n_images, params=params, start_range=start_range)
    indices = Cost_Function.parameter_indices
    # TODO name the constants
    # nex must be > 0.01 to avoid singular F
    Cost_Function.add_affine_constraint(("diffusion", "nex"), "ineq", 1.0, -0.01)
    Cost_Function.add_affine_constraint(("diffusion", "b"), "ineq")
    for prev, next in zip(indices["diffusion"]["b"][:-1], indices["diffusion"]["b"][1:]):
        Cost_Function.constraints.append({"type": "ineq", "fun": lambda x, prev=prev, next=next: x[next] - x[prev]})
    # Fixed time constraint
    # TODO: modify this to account for difference in min_tr bet seq.
    Cost_Function.constraints.append(
        {"type": "eq", "fun": lambda x, nex_idx=indices["diffusion"]["nex"]: sum(x[nex_idx]) - 1.0}
    )
    return Cost_Function