def _get_alt_context(self, ctx):
        """
        returns the context values for this node[ctx] actually
        belong in. This can be different from ctx if its a
        shifted context but this node doesn't depend on that shift.
        """
        ctx_shift_set = ctx.get_shift_set()

        # if the context hasn't been shifted then the context to use
        # is trivially this context
        if not ctx_shift_set:
            return ctx

        # if the node's been overriden get the alt context from the override
        node_state = self._get_state(ctx)
        override_node = self._get_override(ctx, node_state)
        if override_node and override_node is not self:
            override_alt_ctx = cython.declare(MDFContext)
            override_alt_ctx = override_node.get_alt_context(ctx)
            return override_alt_ctx.shift({self : override_node})

        # cython forward declarations
        parent = cython.declare(MDFContext)
        shifted_ctx = cython.declare(MDFContext)
        best_match = cython.declare(MDFContext)
        shifted_node_state = cython.declare(NodeState)
        num_shifts = cython.declare(int)
        best_match_num_shifts = cython.declare(int)
        shifted_node = cython.declare(MDFNode)

        # find the most shifted context where this node has been called
        # and where this context is a shift of that shifted context
        parent = ctx.get_parent() or ctx

        best_match = None
        best_match_num_shifts = -1
        for shifted_ctx in itertools.chain([parent], parent.iter_shifted_contexts()):
            try:
                shifted_node_state = self._states[shifted_ctx._id_obj]
            except __HOLE__:
                continue

            if shifted_node_state.called:
                if shifted_ctx is ctx or ctx.is_shift_of(shifted_ctx):
                    # ctx is a shift of shifted_ctx so use the dependencies
                    # from this context to determine the correct alt context
                    num_shifts = len(shifted_ctx.get_shift_set())
                    if num_shifts > best_match_num_shifts:
                        best_match = shifted_ctx
                        best_match_num_shifts = num_shifts

                        # early out if this context is the main context
                        # since there can't be a candidate that ctx is a
                        # shift of and is more shifted
                        if shifted_ctx is ctx:
                            break

        # if it's never been called before in any related context, use this context
        if best_match is None:
            return ctx

        # get all the contexts that are shifts of the original context (or are the ctx)
        # or that original context is a shift of. i.e. it's a list of all contexts from the root
        # to ctx plus any shifts of ctx.
        #
        # NOTE this is *not* all the shifts and parents of best_match as that could be a much
        # wider set and could include contexts that are actually not shifts or parents of
        # the original context we're trying to get the value in.
        all_shifted_ctxs = cqueue()
        cqueue_push(all_shifted_ctxs, parent)
        for shifted_ctx in parent.iter_shifted_contexts():
            if shifted_ctx is ctx \
            or shifted_ctx.is_shift_of(ctx) \
            or ctx.is_shift_of(shifted_ctx):
                cqueue_push(all_shifted_ctxs, shifted_ctx)

        # sort so the least shifted are at the start. This should be more optimal
        # for the next loop than if they were in a random order.
        def get_shift_degree(x):
            return len(x.get_shift_set())
        cqueue_sort(all_shifted_ctxs, get_shift_degree, False)

        best_match_state = cython.declare(NodeState)
        best_match_state = self._get_state(best_match)

        shift_set = cython.declare(dict)
        shift_set = {}
        for shifted_node, shifted_value in ctx_shift_set.iteritems():
            # if the context is shifted by self then include self in the shift set
            if shifted_node is self:
                shift_set[shifted_node] = shifted_value
                continue

            # if self[best_match] depends on shifted_node[best_match] or
            # on shifted_node[shifted_ctx] where shifted_ctx is any shift
            # of the original ctx then we have to include the shifted node in the
            # shift set
            for shifted_ctx in all_shifted_ctxs:
                if self._depends_on(best_match_state, shifted_node, shifted_ctx._id_obj):
                    shift_set[shifted_node] = shifted_value
                    break

        return parent.shift(shift_set)
dataset/ETHPy150Open manahl/mdf/mdf/nodes.py/MDFEvalNode._get_alt_context