'Return a tensor with free indices substituted according to ``index_tuples``
``index_types`` list of tuples ``(old_index, new_index)``
Examples
>>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensorhead
>>> Lorentz = TensorIndexType(\'Lorentz\', dummy_fmt=\'L\')
>>> i, j, k, l = tensor_indices(\'i,j,k,l\', Lorentz)
>>> A, B = tensorhead(\'A,B\', [Lorentz]*2, [[1]*2])
>>> t = A(i, k)*B(-k, -j); t
A(i, L_0)*B(-L_0, -j)
>>> t.fun_eval((i, k),(-j, l))
A(k, L_0)*B(-L_0, l)'

def fun_eval(self, *index_tuples):

    index_tuples = dict(index_tuples)
    indices = self.get_indices()
    free_ind_set = self._get_free_indices_set()
    for (i, ind) in enumerate(indices):
        if ((ind in index_tuples) and (ind in free_ind_set)):
            indices[i] = index_tuples[ind]
    indstruc = _IndexStructure.from_indices(*indices)
    return self._set_new_index_structure(indstruc)
