Я использую функцию quad
из scipy.integrate v0.19.1
для интеграции функций с сингулярностью, подобной квадратному корню, на каждом конце интервала интегрирования, например,
In [1]: quad(lambda x: 1/sqrt(1-x**2), -1, 1)
(Я использую функцию sqrt
из numpy v1.12.0
), которая немедленно дает правильный результат pi:
Out[1]: (3.141592653589591, 6.200897573194197e-10)
В соответствии с документацией функции quad
ключевое слово points
следует использовать для указания местоположения сингулярностей или разрывов подынтегральной функции, но если я укажу точки [1, -1]
, где указанная выше подынтегральная функция сингулярна, я получу предупреждение и nan
в результате:
In [2]: quad(lambda x: 1/sqrt(1-x**2), -1, 1, points=[-1, 1])
RuntimeWarning: divide by zero encountered in double_scalars
IntegrationWarning: Extremely bad integrand behavior occurs at some
points of the integration interval.
Out[2]: (nan, nan)
Может кто-нибудь пояснить, почему quad
выдает эти проблемы, если указаны особенности подынтегральной функции, и просто работает, если эти точки не указаны?
EDIT: я думаю, что нашел правильное решение этой проблемы. На случай, если кто-то еще столкнется с подобными проблемами, я хочу быстро поделиться своими выводами:
Если вы хотите интегрировать функцию вида f(x)*g(x)
с гладкой функцией f(x)
и g(x) = (x-a)**alpha * (b-x)**beta
, где a
и b
— пределы интегрирования, а g(x)
имеет особенности в этих пределах, если alpha, beta < 0
, то вы должны просто интегрировать f(x)
, используя g(x)
как < em>функция взвешивания. Для подпрограммы quad
это возможно с использованием аргументов weight
и wvar
. С помощью этих аргументов вы также можете обрабатывать сингулярности различных видов и проблематичное колебательное поведение. Весовую функцию g(x)
, определенную выше, можно использовать, установив weight='alg'
и используя wvar=(alpha, beta)
для указания показателей степени в g(x)
.
Поскольку 1/sqrt(1-x**2) = (x+1)**(-1/2) * (1-x)**(-1/2)
теперь я могу обрабатывать интеграл следующим образом:
In [1]: quad(lambda x: 1, -1, 1, weight='alg', wvar=(-1/2, -1/2))
Out[1]: (3.1415926535897927, 9.860180640534107e-14)
который дает правильный ответ pi
с очень высокой точностью, независимо от того, использую ли я аргумент points=(-1, 1)
или нет (который, насколько я теперь понимаю, следует использовать только в том случае, если особенности/разрывы не могут быть обработаны путем выбора подходящего весовая функция).