'Evaluate ``f`` at ``a`` in the given variable.
Examples
>>> from sympy import Poly
>>> from sympy.abc import x, y, z
>>> Poly(x**2 + 2*x + 3, x).eval(2)
11
>>> Poly(2*x*y + 3*x + y + 2, x, y).eval(x, 2)
Poly(5*y + 8, y, domain=\'ZZ\')
>>> f = Poly(2*x*y + 3*x + y + 2*z, x, y, z)
>>> f.eval({x: 2})
Poly(5*y + 2*z + 6, y, z, domain=\'ZZ\')
>>> f.eval({x: 2, y: 5})
Poly(2*z + 31, z, domain=\'ZZ\')
>>> f.eval({x: 2, y: 5, z: 7})
45
>>> f.eval((2, 5))
Poly(2*z + 31, z, domain=\'ZZ\')
>>> f(2, 5)
Poly(2*z + 31, z, domain=\'ZZ\')'

def eval(self, x, a=None, auto=True):

    f = self
    if (a is None):
        if isinstance(x, dict):
            mapping = x
            for (gen, value) in mapping.items():
                f = f.eval(gen, value)
            return f
        elif isinstance(x, (tuple, list)):
            values = x
            if (len(values) > len(f.gens)):
                raise ValueError('too    many    values    provided')
            for (gen, value) in zip(f.gens, values):
                f = f.eval(gen, value)
            return f
        else:
            (j, a) = (0, x)
    else:
        j = f._gen_to_level(x)
    if (not hasattr(f.rep, 'eval')):
        raise OperationNotSupported(f, 'eval')
    try:
        result = f.rep.eval(a, j)
    except CoercionFailed:
        if (not auto):
            raise DomainError(("can't    evaluate    at    %s    in    %s" % (a, f.rep.dom)))
        else:
            (a_domain, [a]) = construct_domain([a])
            new_domain = f.get_domain().unify_with_symbols(a_domain, f.gens)
            f = f.set_domain(new_domain)
            a = new_domain.convert(a, a_domain)
            result = f.rep.eval(a, j)
    return f.per(result, remove=j)
