Find a flux consistent subnetwork containing the core subset.

    The result will contain the core subset and as few of the additional
    reactions as possible.

    Args:
        model: :class:`MetabolicModel` to solve.
        core: Set of core reaction IDs.
        epsilon: Flux threshold value.
        solver: LP solver instance to use.
        scaling: Scaling value to apply (see [Vlassis14]_ for more
            information on this parameter).
        weights: Dictionary with reaction IDs as keys and values as weights.
            Weights specify the cost of adding a reaction to the consistent
            subnetwork. Default value is 1.

    Returns:
        Set of reaction IDs in the consistent reaction subset.

def fastcore(model, core, epsilon, solver, scaling=1e5, weights={}):
    """Find a flux consistent subnetwork containing the core subset.

    The result will contain the core subset and as few of the additional
    reactions as possible.

    Args:
        model: :class:`MetabolicModel` to solve.
        core: Set of core reaction IDs.
        epsilon: Flux threshold value.
        solver: LP solver instance to use.
        scaling: Scaling value to apply (see [Vlassis14]_ for more
            information on this parameter).
        weights: Dictionary with reaction IDs as keys and values as weights.
            Weights specify the cost of adding a reaction to the consistent
            subnetwork. Default value is 1.

    Returns:
        Set of reaction IDs in the consistent reaction subset.
    """
    consistent_subset = set()
    reaction_set = set(model.reactions)

    subset = core - model.reversible
    logger.debug('|J| = {}, J = {}'.format(len(subset), subset))

    penalty_set = reaction_set - core
    logger.debug('|P| = {}, P = {}'.format(len(penalty_set), penalty_set))

    p = FastcoreProblem(model, solver, epsilon=epsilon)
    mode = set(p.find_sparse_mode(subset, penalty_set, scaling, weights))
    if not subset.issubset(mode):
        raise FastcoreError('Inconsistent irreversible core reactions:'
                            ' {}'.format(subset - mode))

    consistent_subset |= mode
    logger.debug('|A| = {}, A = {}'.format(
        len(consistent_subset), consistent_subset))

    subset = core - mode
    logger.debug('|J| = {}, J = {}'.format(len(subset), subset))

    flipped = False
    singleton = False
    while len(subset) > 0:
        penalty_set -= consistent_subset
        if singleton:
            subset_i = set((next(iter(subset)),))
        else:
            subset_i = subset

        mode = set(p.find_sparse_mode(subset_i, penalty_set, scaling, weights))
        consistent_subset.update(mode)
        logger.debug('|A| = {}, A = {}'.format(
            len(consistent_subset), consistent_subset))

        if not subset.isdisjoint(consistent_subset):
            logger.debug('Subset improved {} -> {}'.format(
                len(subset), len(subset - consistent_subset)))
            subset -= consistent_subset
            logger.debug('|J| = {}, J = {}'.format(len(subset), subset))
            flipped = False
        else:
            logger.debug('Nothing found, changing state...')
            subset_rev_i = subset_i & model.reversible
            if flipped or len(subset_rev_i) == 0:
                if singleton:
                    raise FastcoreError('Global network inconsistent:'
                                        ' {}'.format(subset_rev_i))

                logger.debug('Going to non-flipped, singleton state...')
                singleton = True
                flipped = False
            else:
                p.flip(subset_rev_i)
                flipped = True
                logger.debug('Flipped {} reactions'.format(
                    len(subset_rev_i)))

    return consistent_subset