def ostrogradsky_integral(f, x):
num = QQ[x](f.numerator())
den = QQ[x](f.denominator())
q, r = num.quo_rem(den) # целая часть и остаток
# Интегрируем полиномиальную часть
poly_int = sum(q[i] * x^(i+1) / (i+1) for i in range(q.degree()+1))
# Если остаток нулевой, сразу возвращаем
if r == 0:
return poly_int
# Правильная дробь
proper = r / den
alg_part, log_part = ostrogradski(proper, x)
log_aa = FractionField(AA[x])(log_part)
_, partials = log_aa.partial_fraction_decomposition()
log_int = sum(pfdintegral(p, x) for p in partials)
return poly_int + alg_part + log_int