Repository: sympy/sympy
File: sympy/functions/combinatorial/numbers.py (Python)

Code before:
    >>> limit(harmonic(n, 3), n, oo)
    zeta(3)

    For `m > 1`, `H_{n,m}` tends to `\zeta(m)` in the limit of infinite `n`:

    >>> m = Symbol("m", positive=True)
    >>> limit(harmonic(n, m+1), n, oo)
    zeta(m + 1)

    See Also
    ========

    bell, bernoulli, catalan, euler, fibonacci, lucas, genocchi, partition, tribonacci

    References
    ==========

    .. [1] https://en.wikipedia.org/wiki/Harmonic_number
    .. [2] https://functions.wolfram.com/GammaBetaErf/HarmonicNumber/
    .. [3] https://functions.wolfram.com/GammaBetaErf/HarmonicNumber2/

    """

    # This prevents redundant recalculations and speeds up harmonic number computations.
    harmonic_cache: dict[Integer, Callable[[int], Rational]] = {}

    @classmethod
    def eval(cls, n, m=None):
        from sympy.functions.special.zeta_functions import zeta
        if m is S.One:
            return cls(n)
        if m is None:
            m = S.One
        if n.is_zero:
            return S.Zero
        elif m.is_zero:
            return n
        elif n is S.Infinity:
            if m.is_negative:
                return S.NaN
            elif is_le(m, S.One):
                return S.Infinity
            elif is_gt(m, S.One):
                return zeta(m)
        elif m.is_Integer and m.is_nonpositive:
            return (bernoulli(1-m, n+1) - bernoulli(1-m)) / (1-m)
        elif n.is_Integer:
            if n.is_negative and (m.is_integer is False or m.is_nonpositive is False):
                return S.ComplexInfinity if m is S.One else S.NaN
            if n.is_nonnegative:
                if m not in cls.harmonic_cache:

Review comment (performance):
I don't think using `Integer` is appropriate. It's possible for `m` to be a real number, and even if not, it could be given as an `Expr`. If you only want to cache it when it's an `Integer`, you'll need to add a condition to `eval`.


Code after:

    >>> limit(harmonic(n, 3), n, oo)
    zeta(3)

    For `m > 1`, `H_{n,m}` tends to `\zeta(m)` in the limit of infinite `n`:

    >>> m = Symbol("m", positive=True)
    >>> limit(harmonic(n, m+1), n, oo)
    zeta(m + 1)

    See Also
    ========

    bell, bernoulli, catalan, euler, fibonacci, lucas, genocchi, partition, tribonacci

    References
    ==========

    .. [1] https://en.wikipedia.org/wiki/Harmonic_number
    .. [2] https://functions.wolfram.com/GammaBetaErf/HarmonicNumber/
    .. [3] https://functions.wolfram.com/GammaBetaErf/HarmonicNumber2/

    """

    # This prevents redundant recalculations and speeds up harmonic number computations.
    harmonic_cache: dict[Integer, Callable[[int], Rational]] = {}

    @classmethod
    def eval(cls, n, m=None):
        from sympy.functions.special.zeta_functions import zeta
        if m is S.One:
            return cls(n)
        if m is None:
            m = S.One
        if n.is_zero:
            return S.Zero
        elif m.is_zero:
            return n
        elif n is S.Infinity:
            if m.is_negative:
                return S.NaN
            elif is_le(m, S.One):
                return S.Infinity
            elif is_gt(m, S.One):
                return zeta(m)
        elif m.is_Integer and m.is_nonpositive:
            return (bernoulli(1-m, n+1) - bernoulli(1-m)) / (1-m)
        elif n.is_Integer:
            if n.is_negative and (m.is_integer is False or m.is_nonpositive is False):
                return S.ComplexInfinity if m is S.One else S.NaN
            if n.is_nonnegative: