def solve_gfl(data, edges=None, weights=None,
              minlam=0.2, maxlam=1000.0, numlam=30,
              alpha=0.2, inflate=2., converge=1e-6,
              maxsteps=1000000, lam=None, verbose=0,
              missing_val=None, full_path=False,
              loss='normal'):
    '''A very easy-to-use version of GFL solver that just requires the data and
    the edges.'''

    #Fix no edge cases
    if edges.shape[0] < 1:
        return data

    #Keep initial edges
    init_edges = edges

    if verbose:
        print('Decomposing graph into trails')

    if loss == 'binomial':
        flat_data = data[0].flatten()
        nonmissing_flat_data = flat_data, data[1].flatten()
    else:
        flat_data = data.flatten()
        nonmissing_flat_data = flat_data

    if edges is None:
        if loss == 'binomial':
            if verbose:
                print('Using default edge set of a grid of same shape as the data: {0}'.format(data[0].shape))
            edges = hypercube_edges(data[0].shape)
        else:
            if verbose:
                print('Using default edge set of a grid of same shape as the data: {0}'.format(data.shape))
            edges = hypercube_edges(data.shape)
        if missing_val is not None:
            if verbose:
                print('Removing all data points whose data value is {0}'.format(missing_val))
            edges = [(e1,e2) for (e1,e2) in edges if flat_data[e1] != missing_val and flat_data[e2] != missing_val]
            if loss == 'binomial':
                nonmissing_flat_data = flat_data[flat_data != missing_val], nonmissing_flat_data[1][flat_data != missing_val]
            else:
                nonmissing_flat_data = flat_data[flat_data != missing_val]


    ########### Setup the graph
    g = Graph()
    g.add_edges_from(edges)
    chains = decompose_graph(g, heuristic='greedy')
    ntrails, trails, breakpoints, edges = chains_to_trails(chains)

    if verbose:
        print('Setting up trail solver')

    ########### Setup the solver
    if loss == 'normal':
        solver = TrailSolver(alpha, inflate, maxsteps, converge)
    elif loss == 'logistic':
        solver = LogisticTrailSolver(alpha, inflate, maxsteps, converge)
    elif loss == 'binomial':
        solver = BinomialTrailSolver(alpha, inflate, maxsteps, converge)
    else:
        raise NotImplementedError('Loss must be normal, logistic, or binomial')

    # Set the data and pre-cache any necessary structures
    solver.set_data(nonmissing_flat_data, edges, ntrails, trails, breakpoints, weights=weights)

    if verbose:
        print('Solving')

    ########### Run the solver
    if lam:
        # Fixed lambda
        beta = solver.solve(lam)
    else:
        # Grid search to find the best lambda
        beta = solver.solution_path(minlam, maxlam, numlam, verbose=max(0, verbose-1))
        if not full_path:
            beta = beta['best']

    ########### Fix disconnected nodes
    mask = np.ones_like(beta)
    mask[init_edges[:,0]] = 0
    mask[init_edges[:,1]] = 0
    beta[mask>0] = data[mask>0]

    return beta