def _general_pure_index(x: Var, indices_axes: List[int], indices: Var, node_name: str) -> Var:
        """
        General pure index selection

        Case # 1 [Multiple disconnected dimensions selection]:
            a = torch.rand(1,2,3,4)
            index = torch.tensor([0, 1])
            b = a[:,index,:,index]

            In this case, indices is a list [None, [0,1], None, [0,1]]

            b has shape (2,1,3),
            where b[0,:,:] = a[:,0,:,0] and b[1,:,:] = a[:,1,:,1]

        Case # 2 [Multiple connected dimensions selection]:
            a = torch.rand(1,2,3,4)
            index_1 = torch.tensor([0, 1])
            index_2 = torch.tensor([0, 1])
            b = a[:,index_1,index_2,:]

            indices is a list [None, [0, 1], [0, 1], None]

            b has shape (1,2,4),
            where b[:,0,:] = a[:,0,0,:] and b[:,1,:] = a[:,1,1,:]
        """
        # transpose the input tensor to gather the slicing index in front
        is_connected = True
        for i in range(1, len(indices_axes)):
            if indices_axes[i] != indices_axes[i - 1] + 1:
                is_connected = False
                break

        name = node_name + "_transpose" if is_connected else node_name
        perm = indices_axes + [axis for axis in range(x.rank) if axis not in indices_axes]
        x = mb.transpose(x=x, perm=perm)

        if is_current_opset_version_compatible_with(target.iOS17):
            # IOS17 `gather_nd` behaviour is undefined for negative indices.
            cond = mb.greater_equal(x=indices, y=0)
            x_shape = mb.shape(x=x)
            indices_shape = mb.shape(x=indices)
            indices_last_dim = _utils.pymil_value_at(indices_shape, indices.rank - 1)
            indices_last_dim_expand = mb.expand_dims(x=indices_last_dim, axes=[0])
            slice_shape = mb.slice_by_size(x=x_shape, begin=[0], size=indices_last_dim_expand)
            indices = mb.select(
                cond=cond,
                a=indices,
                b=mb.add(x=indices, y=slice_shape),
            )
        result = _utils._construct_gather_op("gather_nd", x, indices, name=name)

        # if the index axes are connect, we need to transpose it back
        if is_connected:
            new_dimensions = list(range(indices_axes[0], indices_axes[0] + indices_rank))
            new_perm = new_dimensions + [
                axis
                for axis in range(x.rank + indices_rank - len(indices_axes))
                if axis not in new_dimensions
            ]
            perm_back = [new_perm.index(axis) for axis in range(len(new_perm))]
            result = mb.transpose(x=result, perm=perm_back, name=node_name)

        return result

        General pure index selection

        Case # 1 [Multiple disconnected dimensions selection]:
            a = torch.rand(1,2,3,4)
            index = torch.tensor([0, 1])
            b = a[:,index,:,index]

            In this case, indices is a list [None, [0,1], None, [0,1]]

            b has shape (2,1,3),
            where b[0,:,:] = a[:,0,:,0] and b[1,:,:] = a[:,1,:,1]

        Case # 2 [Multiple connected dimensions selection]:
            a = torch.rand(1,2,3,4)
            index_1 = torch.tensor([0, 1])
            index_2 = torch.tensor([0, 1])
            b = a[:,index_1,index_2,:]

            indices is a list [None, [0, 1], [0, 1], None]

            b has shape (1,2,4),
            where b[:,0,:] = a[:,0,0,:] and b[:,1,:] = a[:,1,1,:]
        
coremltools/converters/mil/frontend/torch/ops.py