Coverage for src\pqlattice\polynomial\_poly.py: 76%

59 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2026-01-10 12:32 +0100

1import numpy as np 

2from numpy.typing import ArrayLike 

3 

4from .._utils import as_integer 

5from ..typing import Vector, validate_aliases 

6 

7 

8@validate_aliases 

9def make_poly(data: ArrayLike) -> Vector: 

10 """_summary_ 

11 

12 Parameters 

13 ---------- 

14 data : Iterable[int | float] 

15 _description_ 

16 

17 Returns 

18 ------- 

19 Vector 

20 _description_ 

21 

22 Raises 

23 ------ 

24 ValueError 

25 _description_ 

26 """ 

27 arr = as_integer(data) 

28 

29 if arr.ndim != 1: 

30 raise ValueError(f"Expected 1D iterable, got {arr.ndim}D") 

31 

32 return arr 

33 

34 

35@validate_aliases 

36def is_zero_poly(p: Vector) -> bool: 

37 """_summary_ 

38 

39 Parameters 

40 ---------- 

41 p : Vector 

42 _description_ 

43 

44 Returns 

45 ------- 

46 bool 

47 _description_ 

48 

49 Raises 

50 ------ 

51 ValueError 

52 _description_ 

53 """ 

54 if len(p) == 0: 

55 raise ValueError("Empty coefficient array is not a proper polynomial") 

56 

57 return np.count_nonzero(p) == 0 

58 

59 

60@validate_aliases 

61def deg(p: Vector) -> int: 

62 """_summary_ 

63 

64 Parameters 

65 ---------- 

66 p : Vector 

67 _description_ 

68 

69 Returns 

70 ------- 

71 int 

72 _description_ 

73 

74 Raises 

75 ------ 

76 ValueError 

77 _description_ 

78 """ 

79 if len(p) == 0: 

80 raise ValueError("Empty coefficient array is not a proper polynomial") 

81 nonzeros = np.nonzero(p)[0] 

82 if len(nonzeros) == 0: 

83 return -1 

84 # raise ValueError("Degree of zero polynomial is undefined") 

85 else: 

86 return nonzeros[-1] 

87 

88 

89@validate_aliases 

90def pad(p: Vector, max_deg: int) -> Vector: 

91 """_summary_ 

92 

93 Parameters 

94 ---------- 

95 p : Vector 

96 _description_ 

97 max_deg : int 

98 _description_ 

99 

100 Returns 

101 ------- 

102 Vector 

103 _description_ 

104 

105 Raises 

106 ------ 

107 ValueError 

108 _description_ 

109 """ 

110 if is_zero_poly(p): 

111 return zero_poly(max_deg) 

112 

113 d = deg(p) 

114 if max_deg < d: 

115 raise ValueError("max_deg has to be greater or equal to the degree of a given polynomial p") 

116 

117 return as_integer(np.pad(trim(p), (0, max_deg - d))) 

118 

119 

120@validate_aliases 

121def trim(p: Vector) -> Vector: 

122 """_summary_ 

123 

124 Parameters 

125 ---------- 

126 p : Vector 

127 _description_ 

128 

129 Returns 

130 ------- 

131 Vector 

132 _description_ 

133 """ 

134 if is_zero_poly(p): 

135 return as_integer([0]) 

136 

137 return p[: deg(p) + 1].copy() 

138 

139 

140@validate_aliases 

141def add(p: Vector, q: Vector) -> Vector: 

142 """_summary_ 

143 

144 Parameters 

145 ---------- 

146 p : Vector 

147 _description_ 

148 q : Vector 

149 _description_ 

150 

151 Returns 

152 ------- 

153 Vector 

154 _description_ 

155 """ 

156 max_deg = max(deg(p), deg(q), 0) 

157 return trim(pad(p, max_deg) + pad(q, max_deg)) 

158 

159 

160@validate_aliases 

161def sub(p: Vector, q: Vector) -> Vector: 

162 """_summary_ 

163 

164 Parameters 

165 ---------- 

166 p : Vector 

167 _description_ 

168 q : Vector 

169 _description_ 

170 

171 Returns 

172 ------- 

173 Vector 

174 _description_ 

175 """ 

176 max_deg = max(deg(p), deg(q), 0) 

177 return trim(pad(p, max_deg) - pad(q, max_deg)) 

178 

179 

180@validate_aliases 

181def mul(p: Vector, q: Vector) -> Vector: 

182 """_summary_ 

183 

184 Parameters 

185 ---------- 

186 p : Vector 

187 _description_ 

188 q : Vector 

189 _description_ 

190 

191 Returns 

192 ------- 

193 Vector 

194 _description_ 

195 """ 

196 return trim(np.polymul(p[::-1], q[::-1])[::-1]) 

197 

198 

199@validate_aliases 

200def monomial(coeff: int, degree: int) -> Vector: 

201 """_summary_ 

202 

203 Parameters 

204 ---------- 

205 coeff : int 

206 _description_ 

207 degree : int 

208 _description_ 

209 

210 Returns 

211 ------- 

212 Vector 

213 _description_ 

214 

215 Raises 

216 ------ 

217 ValueError 

218 _description_ 

219 """ 

220 if degree < 0: 

221 raise ValueError("degree has to be non negative") 

222 

223 p = as_integer([0] * (degree + 1)) 

224 p[degree] = coeff 

225 return p 

226 

227 

228@validate_aliases 

229def zero_poly(max_deg: int = 0) -> Vector: 

230 """_summary_ 

231 

232 Parameters 

233 ---------- 

234 max_deg : int, optional 

235 _description_, by default 0 

236 

237 Returns 

238 ------- 

239 Vector 

240 _description_ 

241 

242 Raises 

243 ------ 

244 ValueError 

245 _description_ 

246 """ 

247 if max_deg < 0: 

248 raise ValueError("degree has to be non negative") 

249 

250 return as_integer([0] * (max_deg + 1))