Coverage for /usr/lib/python3/dist-packages/sympy/integrals/trigonometry.py: 11%
95 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1from sympy.core import cacheit, Dummy, Ne, Integer, Rational, S, Wild
2from sympy.functions import binomial, sin, cos, Piecewise, Abs
3from .integrals import integrate
5# TODO sin(a*x)*cos(b*x) -> sin((a+b)x) + sin((a-b)x) ?
7# creating, each time, Wild's and sin/cos/Mul is expensive. Also, our match &
8# subs are very slow when not cached, and if we create Wild each time, we
9# effectively block caching.
10#
11# so we cache the pattern
13# need to use a function instead of lamda since hash of lambda changes on
14# each call to _pat_sincos
15def _integer_instance(n):
16 return isinstance(n, Integer)
18@cacheit
19def _pat_sincos(x):
20 a = Wild('a', exclude=[x])
21 n, m = [Wild(s, exclude=[x], properties=[_integer_instance])
22 for s in 'nm']
23 pat = sin(a*x)**n * cos(a*x)**m
24 return pat, a, n, m
26_u = Dummy('u')
29def trigintegrate(f, x, conds='piecewise'):
30 """
31 Integrate f = Mul(trig) over x.
33 Examples
34 ========
36 >>> from sympy import sin, cos, tan, sec
37 >>> from sympy.integrals.trigonometry import trigintegrate
38 >>> from sympy.abc import x
40 >>> trigintegrate(sin(x)*cos(x), x)
41 sin(x)**2/2
43 >>> trigintegrate(sin(x)**2, x)
44 x/2 - sin(x)*cos(x)/2
46 >>> trigintegrate(tan(x)*sec(x), x)
47 1/cos(x)
49 >>> trigintegrate(sin(x)*tan(x), x)
50 -log(sin(x) - 1)/2 + log(sin(x) + 1)/2 - sin(x)
52 References
53 ==========
55 .. [1] https://en.wikibooks.org/wiki/Calculus/Integration_techniques
57 See Also
58 ========
60 sympy.integrals.integrals.Integral.doit
61 sympy.integrals.integrals.Integral
62 """
63 pat, a, n, m = _pat_sincos(x)
65 f = f.rewrite('sincos')
66 M = f.match(pat)
68 if M is None:
69 return
71 n, m = M[n], M[m]
72 if n.is_zero and m.is_zero:
73 return x
74 zz = x if n.is_zero else S.Zero
76 a = M[a]
78 if n.is_odd or m.is_odd:
79 u = _u
80 n_, m_ = n.is_odd, m.is_odd
82 # take smallest n or m -- to choose simplest substitution
83 if n_ and m_:
85 # Make sure to choose the positive one
86 # otherwise an incorrect integral can occur.
87 if n < 0 and m > 0:
88 m_ = True
89 n_ = False
90 elif m < 0 and n > 0:
91 n_ = True
92 m_ = False
93 # Both are negative so choose the smallest n or m
94 # in absolute value for simplest substitution.
95 elif (n < 0 and m < 0):
96 n_ = n > m
97 m_ = not (n > m)
99 # Both n and m are odd and positive
100 else:
101 n_ = (n < m) # NB: careful here, one of the
102 m_ = not (n < m) # conditions *must* be true
104 # n m u=C (n-1)/2 m
105 # S(x) * C(x) dx --> -(1-u^2) * u du
106 if n_:
107 ff = -(1 - u**2)**((n - 1)/2) * u**m
108 uu = cos(a*x)
110 # n m u=S n (m-1)/2
111 # S(x) * C(x) dx --> u * (1-u^2) du
112 elif m_:
113 ff = u**n * (1 - u**2)**((m - 1)/2)
114 uu = sin(a*x)
116 fi = integrate(ff, u) # XXX cyclic deps
117 fx = fi.subs(u, uu)
118 if conds == 'piecewise':
119 return Piecewise((fx / a, Ne(a, 0)), (zz, True))
120 return fx / a
122 # n & m are both even
123 #
124 # 2k 2m 2l 2l
125 # we transform S (x) * C (x) into terms with only S (x) or C (x)
126 #
127 # example:
128 # 100 4 100 2 2 100 4 2
129 # S (x) * C (x) = S (x) * (1-S (x)) = S (x) * (1 + S (x) - 2*S (x))
130 #
131 # 104 102 100
132 # = S (x) - 2*S (x) + S (x)
133 # 2k
134 # then S is integrated with recursive formula
136 # take largest n or m -- to choose simplest substitution
137 n_ = (Abs(n) > Abs(m))
138 m_ = (Abs(m) > Abs(n))
139 res = S.Zero
141 if n_:
142 # 2k 2 k i 2i
143 # C = (1 - S ) = sum(i, (-) * B(k, i) * S )
144 if m > 0:
145 for i in range(0, m//2 + 1):
146 res += (S.NegativeOne**i * binomial(m//2, i) *
147 _sin_pow_integrate(n + 2*i, x))
149 elif m == 0:
150 res = _sin_pow_integrate(n, x)
151 else:
153 # m < 0 , |n| > |m|
154 # /
155 # |
156 # | m n
157 # | cos (x) sin (x) dx =
158 # |
159 # |
160 #/
161 # /
162 # |
163 # -1 m+1 n-1 n - 1 | m+2 n-2
164 # ________ cos (x) sin (x) + _______ | cos (x) sin (x) dx
165 # |
166 # m + 1 m + 1 |
167 # /
169 res = (Rational(-1, m + 1) * cos(x)**(m + 1) * sin(x)**(n - 1) +
170 Rational(n - 1, m + 1) *
171 trigintegrate(cos(x)**(m + 2)*sin(x)**(n - 2), x))
173 elif m_:
174 # 2k 2 k i 2i
175 # S = (1 - C ) = sum(i, (-) * B(k, i) * C )
176 if n > 0:
178 # / /
179 # | |
180 # | m n | -m n
181 # | cos (x)*sin (x) dx or | cos (x) * sin (x) dx
182 # | |
183 # / /
184 #
185 # |m| > |n| ; m, n >0 ; m, n belong to Z - {0}
186 # n 2
187 # sin (x) term is expanded here in terms of cos (x),
188 # and then integrated.
189 #
191 for i in range(0, n//2 + 1):
192 res += (S.NegativeOne**i * binomial(n//2, i) *
193 _cos_pow_integrate(m + 2*i, x))
195 elif n == 0:
197 # /
198 # |
199 # | 1
200 # | _ _ _
201 # | m
202 # | cos (x)
203 # /
204 #
206 res = _cos_pow_integrate(m, x)
207 else:
209 # n < 0 , |m| > |n|
210 # /
211 # |
212 # | m n
213 # | cos (x) sin (x) dx =
214 # |
215 # |
216 #/
217 # /
218 # |
219 # 1 m-1 n+1 m - 1 | m-2 n+2
220 # _______ cos (x) sin (x) + _______ | cos (x) sin (x) dx
221 # |
222 # n + 1 n + 1 |
223 # /
225 res = (Rational(1, n + 1) * cos(x)**(m - 1)*sin(x)**(n + 1) +
226 Rational(m - 1, n + 1) *
227 trigintegrate(cos(x)**(m - 2)*sin(x)**(n + 2), x))
229 else:
230 if m == n:
231 ##Substitute sin(2x)/2 for sin(x)cos(x) and then Integrate.
232 res = integrate((sin(2*x)*S.Half)**m, x)
233 elif (m == -n):
234 if n < 0:
235 # Same as the scheme described above.
236 # the function argument to integrate in the end will
237 # be 1, this cannot be integrated by trigintegrate.
238 # Hence use sympy.integrals.integrate.
239 res = (Rational(1, n + 1) * cos(x)**(m - 1) * sin(x)**(n + 1) +
240 Rational(m - 1, n + 1) *
241 integrate(cos(x)**(m - 2) * sin(x)**(n + 2), x))
242 else:
243 res = (Rational(-1, m + 1) * cos(x)**(m + 1) * sin(x)**(n - 1) +
244 Rational(n - 1, m + 1) *
245 integrate(cos(x)**(m + 2)*sin(x)**(n - 2), x))
246 if conds == 'piecewise':
247 return Piecewise((res.subs(x, a*x) / a, Ne(a, 0)), (zz, True))
248 return res.subs(x, a*x) / a
251def _sin_pow_integrate(n, x):
252 if n > 0:
253 if n == 1:
254 #Recursion break
255 return -cos(x)
257 # n > 0
258 # / /
259 # | |
260 # | n -1 n-1 n - 1 | n-2
261 # | sin (x) dx = ______ cos (x) sin (x) + _______ | sin (x) dx
262 # | |
263 # | n n |
264 #/ /
265 #
266 #
268 return (Rational(-1, n) * cos(x) * sin(x)**(n - 1) +
269 Rational(n - 1, n) * _sin_pow_integrate(n - 2, x))
271 if n < 0:
272 if n == -1:
273 ##Make sure this does not come back here again.
274 ##Recursion breaks here or at n==0.
275 return trigintegrate(1/sin(x), x)
277 # n < 0
278 # / /
279 # | |
280 # | n 1 n+1 n + 2 | n+2
281 # | sin (x) dx = _______ cos (x) sin (x) + _______ | sin (x) dx
282 # | |
283 # | n + 1 n + 1 |
284 #/ /
285 #
287 return (Rational(1, n + 1) * cos(x) * sin(x)**(n + 1) +
288 Rational(n + 2, n + 1) * _sin_pow_integrate(n + 2, x))
290 else:
291 #n == 0
292 #Recursion break.
293 return x
296def _cos_pow_integrate(n, x):
297 if n > 0:
298 if n == 1:
299 #Recursion break.
300 return sin(x)
302 # n > 0
303 # / /
304 # | |
305 # | n 1 n-1 n - 1 | n-2
306 # | sin (x) dx = ______ sin (x) cos (x) + _______ | cos (x) dx
307 # | |
308 # | n n |
309 #/ /
310 #
312 return (Rational(1, n) * sin(x) * cos(x)**(n - 1) +
313 Rational(n - 1, n) * _cos_pow_integrate(n - 2, x))
315 if n < 0:
316 if n == -1:
317 ##Recursion break
318 return trigintegrate(1/cos(x), x)
320 # n < 0
321 # / /
322 # | |
323 # | n -1 n+1 n + 2 | n+2
324 # | cos (x) dx = _______ sin (x) cos (x) + _______ | cos (x) dx
325 # | |
326 # | n + 1 n + 1 |
327 #/ /
328 #
330 return (Rational(-1, n + 1) * sin(x) * cos(x)**(n + 1) +
331 Rational(n + 2, n + 1) * _cos_pow_integrate(n + 2, x))
332 else:
333 # n == 0
334 #Recursion Break.
335 return x