def _step_upper_bound_low_mem(r, m, q, generating_function): r""" Low memory implementation of :func:`_step_upper_bound_internal`. Significantly slower, but the memory footprint does not significantly increase even if the series coefficients need to be computed to very high degree terms. """ L = LieAlgebra(ZZ, ['X_%d' % k for k in range(r)]).Lyndon() dim_fm = L.graded_dimension(m) PR = PolynomialRing(ZZ, 't') t = PR.gen() a = (1 - dim_fm * (1 - t**q)) * t**m b = PR.one() for k in range(1, m): b *= (1 - t**k)**L.graded_dimension(k) # extract initial coefficients from a symbolic series expansion bd = b.degree() id = max(a.degree() + 1, bd) offset = id - bd quot = SR(a / b) sym_t = SR(t) qs = quot.series(sym_t, id) # check if partial sum is positive already within series expansion # store the last offset...id terms to start the linear recurrence coeffs = deque() cumul = ZZ.zero() for s in range(id): c = ZZ(qs.coefficient(sym_t, s)) cumul += c if s >= offset: coeffs.append(c) if cumul > 0: if generating_function: return s, quot return s # the rest of the coefficients are defined by a recurrence relation multipliers = [-b.monomial_coefficient(t**(bd - k)) for k in range(bd)] while cumul <= 0: c_next = sum(c * m for c, m in zip(coeffs, multipliers)) cumul += c_next s += 1 coeffs.append(c_next) coeffs.popleft() if generating_function: return s, quot return s