def _merge_two(res1, res2, compute_aux=False):
    """
    Internal method used to merges two runs with differing (possibly variable)
    numbers of live points into one run.

    Parameters
    ----------
    res1 : :class:`~dynesty.results.Results` instance
        The "base" nested sampling run.

    res2 : :class:`~dynesty.results.Results` instance
        The "new" nested sampling run.

    compute_aux : bool, optional
        Whether to compute auxiliary quantities (evidences, etc.) associated
        with a given run. **WARNING: these are only valid if `res1` or `res2`
        was initialized from the prior *and* their sampling bounds overlap.**
        Default is `False`.

    Returns
    -------
    res : :class:`~dynesty.results.Results` instances
        :class:`~dynesty.results.Results` instance from the newly combined
        nested sampling run.

    """

    # Initialize the first ("base") run.
    base_id = res1.samples_id
    base_u = res1.samples_u
    base_v = res1.samples
    base_logl = res1.logl
    base_nc = res1.ncall
    base_it = res1.samples_it
    nbase = len(base_id)

    # Number of live points throughout the run.
    try:
        base_n = res1.samples_n
    except:
        niter, nlive = res1.niter, res1.nlive
        if nbase == niter:
            base_n = np.ones(niter, dtype='int') * nlive
        elif nbase == (niter + nlive):
            base_n = np.append(np.ones(niter, dtype='int') * nlive,
                               np.arange(1, nlive + 1)[::-1])
        else:
            raise ValueError("Final number of samples differs from number of "
                             "iterations and number of live points in `res1`.")

    # Proposal information (if available).
    try:
        base_prop = res1.prop
        base_propidx = res1.samples_prop
        base_piter = res1.prop_iter
        base_scale = res1.scale
        base_proposals = True
    except:
        base_proposals = False

    # Batch information (if available).
    try:
        base_batch = res1.samples_batch
        base_bounds = res1.batch_bounds
    except:
        base_batch = np.zeros(nbase, dtype='int')
        base_bounds = np.array([(-np.inf, np.inf)])

    # Initialize the second ("new") run.
    new_id = res2.samples_id
    new_u = res2.samples_u
    new_v = res2.samples
    new_logl = res2.logl
    new_nc = res2.ncall
    new_it = res2.samples_it
    nnew = len(new_id)

    # Number of live points throughout the run.
    try:
        new_n = res2.samples_n
    except:
        niter, nlive = res2.niter, res2.nlive
        if nnew == niter:
            new_n = np.ones(niter, dtype='int') * nlive
        elif nnew == (niter + nlive):
            new_n = np.append(np.ones(niter, dtype='int') * nlive,
                              np.arange(1, nlive + 1)[::-1])
        else:
            raise ValueError("Final number of samples differs from number of "
                             "iterations and number of live points in `res2`.")

    # Proposal information (if available).
    try:
        new_prop = res2.prop
        new_propidx = res2.samples_prop
        new_piter = res2.prop_iter
        new_scale = res2.scale
        new_proposals = True
    except:
        new_proposals = False

    # Batch information (if available).
    try:
        new_batch = res2.samples_batch
        new_bounds = res2.batch_bounds
    except:
        new_batch = np.zeros(nnew, dtype='int')
        new_bounds = np.array([(-np.inf, np.inf)])

    # Initialize our new combind run.
    combined_id = []
    combined_u = []
    combined_v = []
    combined_logl = []
    combined_logvol = []
    combined_logwt = []
    combined_logz = []
    combined_logzvar = []
    combined_h = []
    combined_nc = []
    combined_propidx = []
    combined_it = []
    combined_n = []
    combined_piter = []
    combined_scale = []
    combined_batch = []

    # Check if proposal info is the same and modify counters accordingly.
    if base_proposals and new_proposals:
        if base_prop == new_prop:
            prop = base_prop
            poffset = 0
        else:
            prop = np.concatenate((base_prop, new_prop))
            poffset = len(base_prop)

    # Check if batch info is the same and modify counters accordingly.
    if np.all(base_bounds == new_bounds):
        bounds = base_bounds
        boffset = 0
    else:
        bounds = np.concatenate((base_bounds, new_bounds))
        boffset = len(base_bounds)

    # Start our counters at the beginning of each set of dead points.
    idx_base, idx_new = 0, 0
    logl_b, logl_n = base_logl[idx_base], new_logl[idx_new]
    nlive_b, nlive_n = base_n[idx_base], new_n[idx_new]

    # Iteratively walk through both set of samples to simulate
    # a combined run.
    ntot = nbase + nnew
    llmin_b = np.min(base_bounds[base_batch])
    llmin_n = np.min(new_bounds[new_batch])
    logvol = 0.
    for i in range(ntot):
        if logl_b > llmin_n and logl_n > llmin_b:
            # If our samples from the both runs are past the each others'
            # lower log-likelihood bound, both runs are now "active".
            nlive = nlive_b + nlive_n
        elif logl_b <= llmin_n:
            # If instead our collection of dead points from the "base" run
            # are below the bound, just use those.
            nlive = nlive_b
        else:
            # Our collection of dead points from the "new" run
            # are below the bound, so just use those.
            nlive = nlive_n

        # Increment our position along depending on
        # which dead point (saved or new) is worse.
        if logl_b <= logl_n:
            combined_id.append(base_id[idx_base])
            combined_u.append(base_u[idx_base])
            combined_v.append(base_v[idx_base])
            combined_logl.append(base_logl[idx_base])
            combined_nc.append(base_nc[idx_base])
            combined_it.append(base_it[idx_base])
            combined_batch.append(base_batch[idx_base])
            if base_proposals and new_proposals:
                combined_propidx.append(base_propidx[idx_base])
                combined_piter.append(base_piter[idx_base])
                combined_scale.append(base_scale[idx_base])
            idx_base += 1
        else:
            combined_id.append(new_id[idx_new])
            combined_u.append(new_u[idx_new])
            combined_v.append(new_v[idx_new])
            combined_logl.append(new_logl[idx_new])
            combined_nc.append(new_nc[idx_new])
            combined_it.append(new_it[idx_new])
            combined_batch.append(new_batch[idx_new] + boffset)
            if base_proposals and new_proposals:
                combined_propidx.append(new_propidx[idx_new] + poffset)
                combined_piter.append(new_piter[idx_new] + poffset)
                combined_scale.append(new_scale[idx_new])
            idx_new += 1

        # Save the number of live points and expected ln(volume).
        logvol -= math.log((nlive + 1.) / nlive)
        combined_n.append(nlive)
        combined_logvol.append(logvol)

        # Attempt to step along our samples. If we're out of samples,
        # set values to defaults.
        try:
            logl_b = base_logl[idx_base]
            nlive_b = base_n[idx_base]
        except:
            logl_b = np.inf
            nlive_b = 0
        try:
            logl_n = new_logl[idx_new]
            nlive_n = new_n[idx_new]
        except:
            logl_n = np.inf
            nlive_n = 0

    # Compute sampling efficiency.
    eff = 100. * ntot / sum(combined_nc)

    # Save results.
    r = [('niter', ntot),
         ('ncall', np.array(combined_nc)),
         ('eff', eff),
         ('samples', np.array(combined_v)),
         ('samples_id', np.array(combined_id)),
         ('samples_it', np.array(combined_it)),
         ('samples_n', np.array(combined_n)),
         ('samples_u', np.array(combined_u)),
         ('samples_batch', np.array(combined_batch)),
         ('logl', np.array(combined_logl)),
         ('logvol', np.array(combined_logvol)),
         ('batch_bounds', np.array(bounds))]

    # Add proposal information (if available).
    if base_proposals and new_proposals:
        r.append(('prop', prop))
        r.append(('prop_iter', np.array(combined_piter)))
        r.append(('samples_prop', np.array(combined_propidx)))
        r.append(('scale', np.array(combined_scale)))

    # Compute the posterior quantities of interest if desired.
    if compute_aux:
        h = 0.
        logz = -1.e300
        loglstar = -1.e300
        logzvar = 0.
        logvols_pad = np.concatenate(([0.], combined_logvol))
        logdvols = misc.logsumexp(a=np.c_[logvols_pad[:-1], logvols_pad[1:]],
                                  axis=1, b=np.c_[np.ones(ntot),
                                                  -np.ones(ntot)])
        logdvols += math.log(0.5)
        dlvs = logvols_pad[:-1] - logvols_pad[1:]
        for i in range(ntot):
            loglstar_new = combined_logl[i]
            logdvol, dlv = logdvols[i], dlvs[i]
            logwt = np.logaddexp(loglstar_new, loglstar) + logdvol
            logz_new = np.logaddexp(logz, logwt)
            lzterm = (math.exp(loglstar - logz_new) * loglstar +
                      math.exp(loglstar_new - logz_new) * loglstar_new)
            h_new = (math.exp(logdvol) * lzterm +
                     math.exp(logz - logz_new) * (h + logz) -
                     logz_new)
            dh = h_new - h
            h = h_new
            logz = logz_new
            logzvar += dh * dlv
            loglstar = loglstar_new
            combined_logwt.append(logwt)
            combined_logz.append(logz)
            combined_logzvar.append(logzvar)
            combined_h.append(h)

        # Compute batch information.
        combined_id = np.array(combined_id)
        batch_nlive = [len(np.unique(combined_id[combined_batch == i]))
                       for i in np.unique(combined_batch)]

        # Add to our results.
        r.append(('logwt', np.array(combined_logwt)))
        r.append(('logz', np.array(combined_logz)))
        r.append(('logzerr', np.sqrt(np.array(combined_logzvar))))
        r.append(('h', np.array(combined_h)))
        r.append(('batch_nlive', np.array(batch_nlive, dtype='int')))

    # Combine to form final results object.
    res = Results(r)

    return res
Internal method used to merges two runs with differing (possibly variable)
    numbers of live points into one run.

    Parameters
    ----------
    res1 : :class:`~dynesty.results.Results` instance
        The "base" nested sampling run.

    res2 : :class:`~dynesty.results.Results` instance
        The "new" nested sampling run.

    compute_aux : bool, optional
        Whether to compute auxiliary quantities (evidences, etc.) associated
        with a given run. **WARNING: these are only valid if `res1` or `res2`
        was initialized from the prior *and* their sampling bounds overlap.**
        Default is `False`.

    Returns
    -------
    res : :class:`~dynesty.results.Results` instances
        :class:`~dynesty.results.Results` instance from the newly combined
        nested sampling run.