'Evaluate an expression, using the solver if necessary. Returns primitives.
:param e: the expression
:param n: the number of desired solutions
:param extra_constraints: extra constraints to apply to the solver
:param exact: if False, returns approximate solutions
:return: a tuple of the solutions, in the form of Python primitives
:rtype: tuple'

@concrete_path_tuple
@timed_function
@ast_stripping_decorator
@error_converter
def eval(self, e, n, extra_constraints=(), exact=None):

    return self._solver.eval(e, n, extra_constraints=self._adjust_constraint_list(extra_constraints), exact=exact)
