def merge_two_slices(slice1, len1, slice2, len2):
    """
     This function merges two slices into a single slice. The code works on
     the assumption that:

     a) slice1 is actually a slice and not an index, while slice2
        can be just an index.

     b) the two slices **have been applied consecutively** on the same
        tensor

    The output slice is **not** in canonical form, but actually just a slice
    that can be applied to a tensor to produce the same output as applying
    the two consecutive slices.
    ``len1`` is the length of the tensor **before** applying the first slice,
    while ``len2`` is the length **after** applying the first slice.
    """
    list_opt = [local_abs_merge, local_mul_switch_sink,
                local_upcast_elemwise_constant_inputs,
                local_useless_switch, constant_folding]

    if type(slice1) is not slice:
        raise ValueError(('First provided slice should actually be of type'
                         'slice and not an index !'), slice1)
    sl1, reverse1 = get_canonical_form_slice(slice1, len1)
    sl2, reverse2 = get_canonical_form_slice(slice2, len2)

    if type(sl2) is not slice:
        if reverse1 is None:
            # The first slice is not in reverse, which makes things a lot
            # more clear.
            # In this case we need to take care only of the special cases:
            # len2 <=0    -> throw index error regardless of sl2
            # sl2 > len2  -> throw index error
            # sl2 < -len2 -> throw index error
            # To get a index error we simply use len1+1 to indicate we are
            # out of bounds, because passing this index through the formula
            # of getting the mixed slice is not guaranteed to result in an
            # index error. The **issue though** if that the error will
            # complain about accessing element len1+1 which is probably not
            # too intuitive for the user
            val = sl1.start + sl2 * sl1.step
            val = T.switch(T.le(len2, 0), len1 + 1, val)
            val = T.switch(T.ge(sl2, len2), len1 + 1, val)
            val = T.switch(T.lt(sl2, 0), - len1 - 1, val)
            if sl1.step:
                val = T.switch(T.eq(sl1.step, 0), len1 + 1, val)
            return val
        else:
            # We are in the more complex case when we do not actually know
            # if the first slice was in reverse or not.
            # in case it was not in reverse:
            p_val = sl1.start + sl2 * sl1.step
            # case it was in reverse we need to realize that we do not want
            # the k-th element from sl.start but the k-th element from
            # sl.stop backwards
            n_val = sl1.stop - 1 - sl2 * sl1.step
            if config.warn.subtensor_merge_bug:
                _logger.warn((
                    'Your current code is fine, but Theano versions '
                    'prior to 0.5rc2 might have given an incorrect result. '
                    'To disable this warning, set the Theano flag '
                    'warn.subtensor_merge_bug to False.'))
            # we need to pick either n_val or p_val and then follow same
            # steps as above for covering the index error cases
            val = T.switch(T.lt(reverse1, 0), n_val, p_val)
            val = T.switch(T.le(len2, 0), len1 + 1, val)
            val = T.switch(T.ge(sl2, len2), len1 + 1, val)
            val = T.switch(T.lt(sl2, 0), - len1 - 1, val)
            if sl1.step:
                val = T.switch(T.eq(sl1.step, 0), len1 + 1, val)
            return val
    else:
        # We are deleaing with two slices that need to be put together
        # according to the two steps we have 4 different combinations of
        # positive/negative. I will denote the case I'm looking at by
        # suffixes to the variables (nn,np,pn,pp):
        flen = sl2.start - sl2.stop
        p_step = sl1.step * sl2.step
        n_step = sl1.step * sl2.step * -1

        pp_start = T.minimum(sl1.start + sl2.start * sl1.step, sl1.stop)
        pp_stop = T.minimum(sl1.start + sl2.stop * sl1.step, sl1.stop)

        pn_stop = sl1.start + (sl2.start - 1) * sl1.step
        pn_stop = T.switch(T.and_(T.lt(pn_stop, 0),
                                  T.gt(flen, 0)),
                           -len1 - 1,
                           T.minimum(pn_stop, sl1.stop))
        pn_start = sl1.start + (sl2.stop - 1) * sl1.step
        pn_start = T.minimum(pn_start, sl1.stop)
        pn_start = T.maximum(pn_start, 0)

        np_stop = sl1.stop - sl2.stop * sl1.step - 1
        np_stop = T.switch(T.and_(T.lt(np_stop, 0),
                                  T.gt(flen, 0)),
                           -len1 - 1,
                           T.maximum(sl1.start - 1, np_stop))
        np_start = T.maximum(sl1.start, sl1.stop - sl2.start * sl1.step - 1)

        nn_start = T.maximum(sl1.start,
                             (sl1.stop - 1) - (sl2.stop - 1) * sl1.step)
        nn_stop = T.maximum(sl1.start, sl1.stop - sl2.start * sl1.step)

        start = T.switch(T.lt(reverse2 * reverse1, 0),
                         T.switch(T.lt(reverse1, 0), np_start, pn_start),
                         T.switch(T.lt(reverse1, 0), nn_start,
                                  pp_start))

        stop = T.switch(T.lt(reverse2 * reverse1, 0),
                        T.switch(T.lt(reverse1, 0), np_stop, pn_stop),
                        T.switch(T.lt(reverse1, 0), nn_stop, pp_stop))

        step = T.switch(T.lt(reverse2 * reverse1, 0), n_step, p_step)
        start = T.switch(T.le(flen, 0), 0, start)
        stop = T.switch(T.le(flen, 0), 0, stop)

        # The canonical form of the slice is pretty complicated
        # and is not simplified. We simplify it in advance here
        # as otherwise this create too many useless optimization that
        # DebugMode must check.
        start = pre_greedy_local_optimizer(list_opt, start)
        stop = pre_greedy_local_optimizer(list_opt, stop)
        step = pre_greedy_local_optimizer(list_opt, step)
        start = pre_greedy_local_optimizer(list_opt, start)
        stop = pre_greedy_local_optimizer(list_opt, stop)
        step = pre_greedy_local_optimizer(list_opt, step)

        # Pre merge constant for the same reason.
        start, stop, step = pre_constant_merge([start, stop, step])

        return slice(start, stop, step)
dataset/ETHPy150Open rizar/attention-lvcsr/libs/Theano/theano/tensor/opt.py/merge_two_slices/swapped operands of `-`