Coverage for /usr/lib/python3/dist-packages/sympy/functions/elementary/_trigonometric_special.py: 25%

80 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 15:55 +0200

1r"""A module for special angle forumlas for trigonometric functions 

2 

3TODO 

4==== 

5 

6This module should be developed in the future to contain direct squrae root 

7representation of 

8 

9.. math 

10 F(\frac{n}{m} \pi) 

11 

12for every 

13 

14- $m \in \{ 3, 5, 17, 257, 65537 \}$ 

15- $n \in \mathbb{N}$, $0 \le n < m$ 

16- $F \in \{\sin, \cos, \tan, \csc, \sec, \cot\}$ 

17 

18Without multi-step rewrites 

19(e.g. $\tan \to \cos/\sin \to \cos/\sqrt \to \ sqrt$) 

20or using chebyshev identities 

21(e.g. $\cos \to \cos + \cos^2 + \cdots \to \sqrt{} + \sqrt{}^2 + \cdots $), 

22which are trivial to implement in sympy, 

23and had used to give overly complicated expressions. 

24 

25The reference can be found below, if anyone may need help implementing them. 

26 

27References 

28========== 

29 

30.. [*] Gottlieb, Christian. (1999). The Simple and straightforward construction 

31 of the regular 257-gon. The Mathematical Intelligencer. 21. 31-37. 

32 10.1007/BF03024829. 

33.. [*] https://resources.wolframcloud.com/FunctionRepository/resources/Cos2PiOverFermatPrime 

34""" 

35from __future__ import annotations 

36from typing import Callable 

37from functools import reduce 

38from sympy.core.expr import Expr 

39from sympy.core.singleton import S 

40from sympy.core.numbers import igcdex, Integer 

41from sympy.functions.elementary.miscellaneous import sqrt 

42from sympy.core.cache import cacheit 

43 

44 

45def migcdex(*x: int) -> tuple[tuple[int, ...], int]: 

46 r"""Compute extended gcd for multiple integers. 

47 

48 Explanation 

49 =========== 

50 

51 Given the integers $x_1, \cdots, x_n$ and 

52 an extended gcd for multiple arguments are defined as a solution 

53 $(y_1, \cdots, y_n), g$ for the diophantine equation 

54 $x_1 y_1 + \cdots + x_n y_n = g$ such that 

55 $g = \gcd(x_1, \cdots, x_n)$. 

56 

57 Examples 

58 ======== 

59 

60 >>> from sympy.functions.elementary._trigonometric_special import migcdex 

61 >>> migcdex() 

62 ((), 0) 

63 >>> migcdex(4) 

64 ((1,), 4) 

65 >>> migcdex(4, 6) 

66 ((-1, 1), 2) 

67 >>> migcdex(6, 10, 15) 

68 ((1, 1, -1), 1) 

69 """ 

70 if not x: 

71 return (), 0 

72 

73 if len(x) == 1: 

74 return (1,), x[0] 

75 

76 if len(x) == 2: 

77 u, v, h = igcdex(x[0], x[1]) 

78 return (u, v), h 

79 

80 y, g = migcdex(*x[1:]) 

81 u, v, h = igcdex(x[0], g) 

82 return (u, *(v * i for i in y)), h 

83 

84 

85def ipartfrac(*denoms: int) -> tuple[int, ...]: 

86 r"""Compute the the partial fraction decomposition. 

87 

88 Explanation 

89 =========== 

90 

91 Given a rational number $\frac{1}{q_1 \cdots q_n}$ where all 

92 $q_1, \cdots, q_n$ are pairwise coprime, 

93 

94 A partial fraction decomposition is defined as 

95 

96 .. math:: 

97 \frac{1}{q_1 \cdots q_n} = \frac{p_1}{q_1} + \cdots + \frac{p_n}{q_n} 

98 

99 And it can be derived from solving the following diophantine equation for 

100 the $p_1, \cdots, p_n$ 

101 

102 .. math:: 

103 1 = p_1 \prod_{i \ne 1}q_i + \cdots + p_n \prod_{i \ne n}q_i 

104 

105 Where $q_1, \cdots, q_n$ being pairwise coprime implies 

106 $\gcd(\prod_{i \ne 1}q_i, \cdots, \prod_{i \ne n}q_i) = 1$, 

107 which guarantees the existance of the solution. 

108 

109 It is sufficient to compute partial fraction decomposition only 

110 for numerator $1$ because partial fraction decomposition for any 

111 $\frac{n}{q_1 \cdots q_n}$ can be easily computed by multiplying 

112 the result by $n$ afterwards. 

113 

114 Parameters 

115 ========== 

116 

117 denoms : int 

118 The pairwise coprime integer denominators $q_i$ which defines the 

119 rational number $\frac{1}{q_1 \cdots q_n}$ 

120 

121 Returns 

122 ======= 

123 

124 tuple[int, ...] 

125 The list of numerators which semantically corresponds to $p_i$ of the 

126 partial fraction decomposition 

127 $\frac{1}{q_1 \cdots q_n} = \frac{p_1}{q_1} + \cdots + \frac{p_n}{q_n}$ 

128 

129 Examples 

130 ======== 

131 

132 >>> from sympy import Rational, Mul 

133 >>> from sympy.functions.elementary._trigonometric_special import ipartfrac 

134 

135 >>> denoms = 2, 3, 5 

136 >>> numers = ipartfrac(2, 3, 5) 

137 >>> numers 

138 (1, 7, -14) 

139 

140 >>> Rational(1, Mul(*denoms)) 

141 1/30 

142 >>> out = 0 

143 >>> for n, d in zip(numers, denoms): 

144 ... out += Rational(n, d) 

145 >>> out 

146 1/30 

147 """ 

148 if not denoms: 

149 return () 

150 

151 def mul(x: int, y: int) -> int: 

152 return x * y 

153 

154 denom = reduce(mul, denoms) 

155 a = [denom // x for x in denoms] 

156 h, _ = migcdex(*a) 

157 return h 

158 

159 

160def fermat_coords(n: int) -> list[int] | None: 

161 """If n can be factored in terms of Fermat primes with 

162 multiplicity of each being 1, return those primes, else 

163 None 

164 """ 

165 primes = [] 

166 for p in [3, 5, 17, 257, 65537]: 

167 quotient, remainder = divmod(n, p) 

168 if remainder == 0: 

169 n = quotient 

170 primes.append(p) 

171 if n == 1: 

172 return primes 

173 return None 

174 

175 

176@cacheit 

177def cos_3() -> Expr: 

178 r"""Computes $\cos \frac{\pi}{3}$ in square roots""" 

179 return S.Half 

180 

181 

182@cacheit 

183def cos_5() -> Expr: 

184 r"""Computes $\cos \frac{\pi}{5}$ in square roots""" 

185 return (sqrt(5) + 1) / 4 

186 

187 

188@cacheit 

189def cos_17() -> Expr: 

190 r"""Computes $\cos \frac{\pi}{17}$ in square roots""" 

191 return sqrt( 

192 (15 + sqrt(17)) / 32 + sqrt(2) * (sqrt(17 - sqrt(17)) + 

193 sqrt(sqrt(2) * (-8 * sqrt(17 + sqrt(17)) - (1 - sqrt(17)) 

194 * sqrt(17 - sqrt(17))) + 6 * sqrt(17) + 34)) / 32) 

195 

196 

197@cacheit 

198def cos_257() -> Expr: 

199 r"""Computes $\cos \frac{\pi}{257}$ in square roots 

200 

201 References 

202 ========== 

203 

204 .. [*] https://math.stackexchange.com/questions/516142/how-does-cos2-pi-257-look-like-in-real-radicals 

205 .. [*] https://r-knott.surrey.ac.uk/Fibonacci/simpleTrig.html 

206 """ 

207 def f1(a: Expr, b: Expr) -> tuple[Expr, Expr]: 

208 return (a + sqrt(a**2 + b)) / 2, (a - sqrt(a**2 + b)) / 2 

209 

210 def f2(a: Expr, b: Expr) -> Expr: 

211 return (a - sqrt(a**2 + b))/2 

212 

213 t1, t2 = f1(S.NegativeOne, Integer(256)) 

214 z1, z3 = f1(t1, Integer(64)) 

215 z2, z4 = f1(t2, Integer(64)) 

216 y1, y5 = f1(z1, 4*(5 + t1 + 2*z1)) 

217 y6, y2 = f1(z2, 4*(5 + t2 + 2*z2)) 

218 y3, y7 = f1(z3, 4*(5 + t1 + 2*z3)) 

219 y8, y4 = f1(z4, 4*(5 + t2 + 2*z4)) 

220 x1, x9 = f1(y1, -4*(t1 + y1 + y3 + 2*y6)) 

221 x2, x10 = f1(y2, -4*(t2 + y2 + y4 + 2*y7)) 

222 x3, x11 = f1(y3, -4*(t1 + y3 + y5 + 2*y8)) 

223 x4, x12 = f1(y4, -4*(t2 + y4 + y6 + 2*y1)) 

224 x5, x13 = f1(y5, -4*(t1 + y5 + y7 + 2*y2)) 

225 x6, x14 = f1(y6, -4*(t2 + y6 + y8 + 2*y3)) 

226 x15, x7 = f1(y7, -4*(t1 + y7 + y1 + 2*y4)) 

227 x8, x16 = f1(y8, -4*(t2 + y8 + y2 + 2*y5)) 

228 v1 = f2(x1, -4*(x1 + x2 + x3 + x6)) 

229 v2 = f2(x2, -4*(x2 + x3 + x4 + x7)) 

230 v3 = f2(x8, -4*(x8 + x9 + x10 + x13)) 

231 v4 = f2(x9, -4*(x9 + x10 + x11 + x14)) 

232 v5 = f2(x10, -4*(x10 + x11 + x12 + x15)) 

233 v6 = f2(x16, -4*(x16 + x1 + x2 + x5)) 

234 u1 = -f2(-v1, -4*(v2 + v3)) 

235 u2 = -f2(-v4, -4*(v5 + v6)) 

236 w1 = -2*f2(-u1, -4*u2) 

237 return sqrt(sqrt(2)*sqrt(w1 + 4)/8 + S.Half) 

238 

239 

240def cos_table() -> dict[int, Callable[[], Expr]]: 

241 r"""Lazily evaluated table for $\cos \frac{\pi}{n}$ in square roots for 

242 $n \in \{3, 5, 17, 257, 65537\}$. 

243 

244 Notes 

245 ===== 

246 

247 65537 is the only other known Fermat prime and it is nearly impossible to 

248 build in the current SymPy due to performance issues. 

249 

250 References 

251 ========== 

252 

253 https://r-knott.surrey.ac.uk/Fibonacci/simpleTrig.html 

254 """ 

255 return { 

256 3: cos_3, 

257 5: cos_5, 

258 17: cos_17, 

259 257: cos_257 

260 }