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

1from sympy.core import cacheit, Dummy, Ne, Integer, Rational, S, Wild 

2from sympy.functions import binomial, sin, cos, Piecewise, Abs 

3from .integrals import integrate 

4 

5# TODO sin(a*x)*cos(b*x) -> sin((a+b)x) + sin((a-b)x) ? 

6 

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 

12 

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) 

17 

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 

25 

26_u = Dummy('u') 

27 

28 

29def trigintegrate(f, x, conds='piecewise'): 

30 """ 

31 Integrate f = Mul(trig) over x. 

32 

33 Examples 

34 ======== 

35 

36 >>> from sympy import sin, cos, tan, sec 

37 >>> from sympy.integrals.trigonometry import trigintegrate 

38 >>> from sympy.abc import x 

39 

40 >>> trigintegrate(sin(x)*cos(x), x) 

41 sin(x)**2/2 

42 

43 >>> trigintegrate(sin(x)**2, x) 

44 x/2 - sin(x)*cos(x)/2 

45 

46 >>> trigintegrate(tan(x)*sec(x), x) 

47 1/cos(x) 

48 

49 >>> trigintegrate(sin(x)*tan(x), x) 

50 -log(sin(x) - 1)/2 + log(sin(x) + 1)/2 - sin(x) 

51 

52 References 

53 ========== 

54 

55 .. [1] https://en.wikibooks.org/wiki/Calculus/Integration_techniques 

56 

57 See Also 

58 ======== 

59 

60 sympy.integrals.integrals.Integral.doit 

61 sympy.integrals.integrals.Integral 

62 """ 

63 pat, a, n, m = _pat_sincos(x) 

64 

65 f = f.rewrite('sincos') 

66 M = f.match(pat) 

67 

68 if M is None: 

69 return 

70 

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 

75 

76 a = M[a] 

77 

78 if n.is_odd or m.is_odd: 

79 u = _u 

80 n_, m_ = n.is_odd, m.is_odd 

81 

82 # take smallest n or m -- to choose simplest substitution 

83 if n_ and m_: 

84 

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) 

98 

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 

103 

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) 

109 

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) 

115 

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 

121 

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 

135 

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 

140 

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)) 

148 

149 elif m == 0: 

150 res = _sin_pow_integrate(n, x) 

151 else: 

152 

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 # / 

168 

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)) 

172 

173 elif m_: 

174 # 2k 2 k i 2i 

175 # S = (1 - C ) = sum(i, (-) * B(k, i) * C ) 

176 if n > 0: 

177 

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 # 

190 

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)) 

194 

195 elif n == 0: 

196 

197 # / 

198 # | 

199 # | 1 

200 # | _ _ _ 

201 # | m 

202 # | cos (x) 

203 # / 

204 # 

205 

206 res = _cos_pow_integrate(m, x) 

207 else: 

208 

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 # / 

224 

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)) 

228 

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 

249 

250 

251def _sin_pow_integrate(n, x): 

252 if n > 0: 

253 if n == 1: 

254 #Recursion break 

255 return -cos(x) 

256 

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 # 

267 

268 return (Rational(-1, n) * cos(x) * sin(x)**(n - 1) + 

269 Rational(n - 1, n) * _sin_pow_integrate(n - 2, x)) 

270 

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) 

276 

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 # 

286 

287 return (Rational(1, n + 1) * cos(x) * sin(x)**(n + 1) + 

288 Rational(n + 2, n + 1) * _sin_pow_integrate(n + 2, x)) 

289 

290 else: 

291 #n == 0 

292 #Recursion break. 

293 return x 

294 

295 

296def _cos_pow_integrate(n, x): 

297 if n > 0: 

298 if n == 1: 

299 #Recursion break. 

300 return sin(x) 

301 

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 # 

311 

312 return (Rational(1, n) * sin(x) * cos(x)**(n - 1) + 

313 Rational(n - 1, n) * _cos_pow_integrate(n - 2, x)) 

314 

315 if n < 0: 

316 if n == -1: 

317 ##Recursion break 

318 return trigintegrate(1/cos(x), x) 

319 

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 # 

329 

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