passagemath-flint 10.6.1rc10__cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (360) hide show
  1. passagemath_flint-10.6.1rc10.dist-info/METADATA +122 -0
  2. passagemath_flint-10.6.1rc10.dist-info/RECORD +360 -0
  3. passagemath_flint-10.6.1rc10.dist-info/WHEEL +6 -0
  4. passagemath_flint-10.6.1rc10.dist-info/top_level.txt +2 -0
  5. passagemath_flint.libs/libflint-3701249d.so.21.0.0 +0 -0
  6. passagemath_flint.libs/libgf2x-fbd36f80.so.3.0.0 +0 -0
  7. passagemath_flint.libs/libgfortran-8a9a71bc.so.5.0.0 +0 -0
  8. passagemath_flint.libs/libgmp-93ebf16a.so.10.5.0 +0 -0
  9. passagemath_flint.libs/libgsl-e3525837.so.28.0.0 +0 -0
  10. passagemath_flint.libs/libmpfi-ad12a86d.so.0.0.0 +0 -0
  11. passagemath_flint.libs/libmpfr-e0f11cf3.so.6.2.1 +0 -0
  12. passagemath_flint.libs/libntl-1004113e.so.44.0.1 +0 -0
  13. passagemath_flint.libs/libopenblasp-r0-4c5b64b1.3.29.so +0 -0
  14. sage/all__sagemath_flint.py +29 -0
  15. sage/combinat/all__sagemath_flint.py +1 -0
  16. sage/combinat/posets/all__sagemath_flint.py +1 -0
  17. sage/combinat/posets/hasse_cython_flint.cpython-313-aarch64-linux-gnu.so +0 -0
  18. sage/combinat/posets/hasse_cython_flint.pyx +194 -0
  19. sage/data_structures/all__sagemath_flint.py +1 -0
  20. sage/data_structures/bounded_integer_sequences.cpython-313-aarch64-linux-gnu.so +0 -0
  21. sage/data_structures/bounded_integer_sequences.pxd +62 -0
  22. sage/data_structures/bounded_integer_sequences.pyx +1418 -0
  23. sage/graphs/all__sagemath_flint.py +1 -0
  24. sage/graphs/chrompoly.cpython-313-aarch64-linux-gnu.so +0 -0
  25. sage/graphs/chrompoly.pyx +555 -0
  26. sage/graphs/matchpoly.cpython-313-aarch64-linux-gnu.so +0 -0
  27. sage/graphs/matchpoly.pyx +412 -0
  28. sage/libs/all__sagemath_flint.py +17 -0
  29. sage/libs/arb/__init__.py +1 -0
  30. sage/libs/arb/acb.pxd +154 -0
  31. sage/libs/arb/acb_calc.pxd +9 -0
  32. sage/libs/arb/acb_elliptic.pxd +25 -0
  33. sage/libs/arb/acb_hypgeom.pxd +74 -0
  34. sage/libs/arb/acb_mat.pxd +62 -0
  35. sage/libs/arb/acb_modular.pxd +17 -0
  36. sage/libs/arb/acb_poly.pxd +216 -0
  37. sage/libs/arb/arb.pxd +240 -0
  38. sage/libs/arb/arb_fmpz_poly.pxd +21 -0
  39. sage/libs/arb/arb_hypgeom.pxd +83 -0
  40. sage/libs/arb/arb_wrap.h +34 -0
  41. sage/libs/arb/arf.pxd +131 -0
  42. sage/libs/arb/arith.cpython-313-aarch64-linux-gnu.so +0 -0
  43. sage/libs/arb/arith.pyx +87 -0
  44. sage/libs/arb/bernoulli.pxd +6 -0
  45. sage/libs/arb/mag.pxd +77 -0
  46. sage/libs/arb/types.pxd +37 -0
  47. sage/libs/flint/__init__.py +1 -0
  48. sage/libs/flint/acb.pxd +270 -0
  49. sage/libs/flint/acb_calc.pxd +22 -0
  50. sage/libs/flint/acb_dft.pxd +51 -0
  51. sage/libs/flint/acb_dirichlet.pxd +112 -0
  52. sage/libs/flint/acb_elliptic.pxd +42 -0
  53. sage/libs/flint/acb_hypgeom.pxd +169 -0
  54. sage/libs/flint/acb_macros.pxd +9 -0
  55. sage/libs/flint/acb_mat.pxd +136 -0
  56. sage/libs/flint/acb_mat_macros.pxd +10 -0
  57. sage/libs/flint/acb_modular.pxd +62 -0
  58. sage/libs/flint/acb_poly.pxd +251 -0
  59. sage/libs/flint/acb_poly_macros.pxd +8 -0
  60. sage/libs/flint/acb_theta.pxd +124 -0
  61. sage/libs/flint/acf.pxd +32 -0
  62. sage/libs/flint/aprcl.pxd +84 -0
  63. sage/libs/flint/arb.pxd +382 -0
  64. sage/libs/flint/arb_calc.pxd +31 -0
  65. sage/libs/flint/arb_fmpz_poly.pxd +34 -0
  66. sage/libs/flint/arb_fpwrap.pxd +215 -0
  67. sage/libs/flint/arb_hypgeom.pxd +147 -0
  68. sage/libs/flint/arb_macros.pxd +9 -0
  69. sage/libs/flint/arb_mat.pxd +140 -0
  70. sage/libs/flint/arb_mat_macros.pxd +10 -0
  71. sage/libs/flint/arb_poly.pxd +237 -0
  72. sage/libs/flint/arf.pxd +167 -0
  73. sage/libs/flint/arith.cpython-313-aarch64-linux-gnu.so +0 -0
  74. sage/libs/flint/arith.pxd +76 -0
  75. sage/libs/flint/arith.pyx +77 -0
  76. sage/libs/flint/arith_sage.cpython-313-aarch64-linux-gnu.so +0 -0
  77. sage/libs/flint/arith_sage.pyx +308 -0
  78. sage/libs/flint/bernoulli.pxd +28 -0
  79. sage/libs/flint/bool_mat.pxd +52 -0
  80. sage/libs/flint/ca.pxd +203 -0
  81. sage/libs/flint/ca_ext.pxd +34 -0
  82. sage/libs/flint/ca_field.pxd +32 -0
  83. sage/libs/flint/ca_mat.pxd +117 -0
  84. sage/libs/flint/ca_poly.pxd +104 -0
  85. sage/libs/flint/ca_vec.pxd +46 -0
  86. sage/libs/flint/calcium.pxd +27 -0
  87. sage/libs/flint/d_mat.pxd +39 -0
  88. sage/libs/flint/d_vec.pxd +32 -0
  89. sage/libs/flint/dirichlet.pxd +57 -0
  90. sage/libs/flint/dlog.pxd +53 -0
  91. sage/libs/flint/double_extras.pxd +24 -0
  92. sage/libs/flint/double_interval.pxd +36 -0
  93. sage/libs/flint/fexpr.pxd +104 -0
  94. sage/libs/flint/fexpr_builtin.pxd +20 -0
  95. sage/libs/flint/fft.pxd +66 -0
  96. sage/libs/flint/flint.pxd +36 -0
  97. sage/libs/flint/flint_ntl_wrap.h +35 -0
  98. sage/libs/flint/flint_sage.cpython-313-aarch64-linux-gnu.so +0 -0
  99. sage/libs/flint/flint_sage.pyx +163 -0
  100. sage/libs/flint/flint_wrap.h +190 -0
  101. sage/libs/flint/fmpq.pxd +137 -0
  102. sage/libs/flint/fmpq_mat.pxd +105 -0
  103. sage/libs/flint/fmpq_mat_macros.pxd +10 -0
  104. sage/libs/flint/fmpq_mpoly.pxd +165 -0
  105. sage/libs/flint/fmpq_mpoly_factor.pxd +30 -0
  106. sage/libs/flint/fmpq_poly.pxd +241 -0
  107. sage/libs/flint/fmpq_poly_macros.pxd +9 -0
  108. sage/libs/flint/fmpq_poly_sage.cpython-313-aarch64-linux-gnu.so +0 -0
  109. sage/libs/flint/fmpq_poly_sage.pxd +31 -0
  110. sage/libs/flint/fmpq_poly_sage.pyx +48 -0
  111. sage/libs/flint/fmpq_vec.pxd +27 -0
  112. sage/libs/flint/fmpz.pxd +256 -0
  113. sage/libs/flint/fmpz_extras.pxd +32 -0
  114. sage/libs/flint/fmpz_factor.pxd +42 -0
  115. sage/libs/flint/fmpz_factor_sage.cpython-313-aarch64-linux-gnu.so +0 -0
  116. sage/libs/flint/fmpz_factor_sage.pxd +4 -0
  117. sage/libs/flint/fmpz_factor_sage.pyx +29 -0
  118. sage/libs/flint/fmpz_lll.pxd +49 -0
  119. sage/libs/flint/fmpz_macros.pxd +8 -0
  120. sage/libs/flint/fmpz_mat.pxd +184 -0
  121. sage/libs/flint/fmpz_mat_macros.pxd +10 -0
  122. sage/libs/flint/fmpz_mod.pxd +46 -0
  123. sage/libs/flint/fmpz_mod_mat.pxd +71 -0
  124. sage/libs/flint/fmpz_mod_mpoly.pxd +161 -0
  125. sage/libs/flint/fmpz_mod_mpoly_factor.pxd +28 -0
  126. sage/libs/flint/fmpz_mod_poly.pxd +249 -0
  127. sage/libs/flint/fmpz_mod_poly_factor.pxd +46 -0
  128. sage/libs/flint/fmpz_mod_vec.pxd +27 -0
  129. sage/libs/flint/fmpz_mpoly.pxd +224 -0
  130. sage/libs/flint/fmpz_mpoly_factor.pxd +29 -0
  131. sage/libs/flint/fmpz_mpoly_q.pxd +57 -0
  132. sage/libs/flint/fmpz_poly.cpython-313-aarch64-linux-gnu.so +0 -0
  133. sage/libs/flint/fmpz_poly.pxd +407 -0
  134. sage/libs/flint/fmpz_poly.pyx +19 -0
  135. sage/libs/flint/fmpz_poly_factor.pxd +33 -0
  136. sage/libs/flint/fmpz_poly_macros.pxd +8 -0
  137. sage/libs/flint/fmpz_poly_mat.pxd +71 -0
  138. sage/libs/flint/fmpz_poly_q.pxd +55 -0
  139. sage/libs/flint/fmpz_poly_sage.cpython-313-aarch64-linux-gnu.so +0 -0
  140. sage/libs/flint/fmpz_poly_sage.pxd +20 -0
  141. sage/libs/flint/fmpz_poly_sage.pyx +500 -0
  142. sage/libs/flint/fmpz_vec.pxd +80 -0
  143. sage/libs/flint/fmpzi.pxd +52 -0
  144. sage/libs/flint/fq.pxd +97 -0
  145. sage/libs/flint/fq_default.pxd +84 -0
  146. sage/libs/flint/fq_default_mat.pxd +70 -0
  147. sage/libs/flint/fq_default_poly.pxd +97 -0
  148. sage/libs/flint/fq_default_poly_factor.pxd +39 -0
  149. sage/libs/flint/fq_embed.pxd +28 -0
  150. sage/libs/flint/fq_mat.pxd +83 -0
  151. sage/libs/flint/fq_nmod.pxd +95 -0
  152. sage/libs/flint/fq_nmod_embed.pxd +28 -0
  153. sage/libs/flint/fq_nmod_mat.pxd +83 -0
  154. sage/libs/flint/fq_nmod_mpoly.pxd +130 -0
  155. sage/libs/flint/fq_nmod_mpoly_factor.pxd +28 -0
  156. sage/libs/flint/fq_nmod_poly.pxd +202 -0
  157. sage/libs/flint/fq_nmod_poly_factor.pxd +47 -0
  158. sage/libs/flint/fq_nmod_vec.pxd +33 -0
  159. sage/libs/flint/fq_poly.pxd +204 -0
  160. sage/libs/flint/fq_poly_factor.pxd +47 -0
  161. sage/libs/flint/fq_vec.pxd +33 -0
  162. sage/libs/flint/fq_zech.pxd +99 -0
  163. sage/libs/flint/fq_zech_embed.pxd +28 -0
  164. sage/libs/flint/fq_zech_mat.pxd +78 -0
  165. sage/libs/flint/fq_zech_poly.pxd +198 -0
  166. sage/libs/flint/fq_zech_poly_factor.pxd +47 -0
  167. sage/libs/flint/fq_zech_vec.pxd +33 -0
  168. sage/libs/flint/gr.pxd +174 -0
  169. sage/libs/flint/gr_generic.pxd +215 -0
  170. sage/libs/flint/gr_mat.pxd +161 -0
  171. sage/libs/flint/gr_mpoly.pxd +68 -0
  172. sage/libs/flint/gr_poly.pxd +276 -0
  173. sage/libs/flint/gr_special.pxd +237 -0
  174. sage/libs/flint/gr_vec.pxd +120 -0
  175. sage/libs/flint/hypgeom.pxd +24 -0
  176. sage/libs/flint/long_extras.pxd +23 -0
  177. sage/libs/flint/mag.pxd +131 -0
  178. sage/libs/flint/mag_macros.pxd +8 -0
  179. sage/libs/flint/mpf_mat.pxd +36 -0
  180. sage/libs/flint/mpf_vec.pxd +34 -0
  181. sage/libs/flint/mpfr_mat.pxd +27 -0
  182. sage/libs/flint/mpfr_vec.pxd +25 -0
  183. sage/libs/flint/mpn_extras.pxd +41 -0
  184. sage/libs/flint/mpoly.pxd +72 -0
  185. sage/libs/flint/nf.pxd +19 -0
  186. sage/libs/flint/nf_elem.pxd +74 -0
  187. sage/libs/flint/nmod.pxd +35 -0
  188. sage/libs/flint/nmod_mat.pxd +104 -0
  189. sage/libs/flint/nmod_mpoly.pxd +144 -0
  190. sage/libs/flint/nmod_mpoly_factor.pxd +28 -0
  191. sage/libs/flint/nmod_poly.pxd +339 -0
  192. sage/libs/flint/nmod_poly_factor.pxd +44 -0
  193. sage/libs/flint/nmod_poly_linkage.pxi +710 -0
  194. sage/libs/flint/nmod_poly_mat.pxd +76 -0
  195. sage/libs/flint/nmod_vec.pxd +40 -0
  196. sage/libs/flint/ntl_interface.pxd +17 -0
  197. sage/libs/flint/padic.pxd +93 -0
  198. sage/libs/flint/padic_mat.pxd +64 -0
  199. sage/libs/flint/padic_poly.pxd +88 -0
  200. sage/libs/flint/partitions.pxd +23 -0
  201. sage/libs/flint/perm.pxd +26 -0
  202. sage/libs/flint/profiler.pxd +24 -0
  203. sage/libs/flint/qadic.pxd +77 -0
  204. sage/libs/flint/qfb.pxd +44 -0
  205. sage/libs/flint/qqbar.pxd +172 -0
  206. sage/libs/flint/qsieve.cpython-313-aarch64-linux-gnu.so +0 -0
  207. sage/libs/flint/qsieve.pxd +41 -0
  208. sage/libs/flint/qsieve.pyx +21 -0
  209. sage/libs/flint/qsieve_sage.cpython-313-aarch64-linux-gnu.so +0 -0
  210. sage/libs/flint/qsieve_sage.pyx +67 -0
  211. sage/libs/flint/thread_pool.pxd +25 -0
  212. sage/libs/flint/types.pxd +2076 -0
  213. sage/libs/flint/ulong_extras.cpython-313-aarch64-linux-gnu.so +0 -0
  214. sage/libs/flint/ulong_extras.pxd +141 -0
  215. sage/libs/flint/ulong_extras.pyx +21 -0
  216. sage/libs/flint/ulong_extras_sage.cpython-313-aarch64-linux-gnu.so +0 -0
  217. sage/libs/flint/ulong_extras_sage.pyx +21 -0
  218. sage/matrix/all__sagemath_flint.py +1 -0
  219. sage/matrix/change_ring.cpython-313-aarch64-linux-gnu.so +0 -0
  220. sage/matrix/change_ring.pyx +43 -0
  221. sage/matrix/matrix_complex_ball_dense.cpython-313-aarch64-linux-gnu.so +0 -0
  222. sage/matrix/matrix_complex_ball_dense.pxd +14 -0
  223. sage/matrix/matrix_complex_ball_dense.pyx +973 -0
  224. sage/matrix/matrix_cyclo_dense.cpython-313-aarch64-linux-gnu.so +0 -0
  225. sage/matrix/matrix_cyclo_dense.pxd +16 -0
  226. sage/matrix/matrix_cyclo_dense.pyx +1761 -0
  227. sage/matrix/matrix_integer_dense.cpython-313-aarch64-linux-gnu.so +0 -0
  228. sage/matrix/matrix_integer_dense.pxd +32 -0
  229. sage/matrix/matrix_integer_dense.pyx +5801 -0
  230. sage/matrix/matrix_integer_dense_hnf.py +1294 -0
  231. sage/matrix/matrix_integer_dense_saturation.py +346 -0
  232. sage/matrix/matrix_integer_sparse.cpython-313-aarch64-linux-gnu.so +0 -0
  233. sage/matrix/matrix_integer_sparse.pxd +9 -0
  234. sage/matrix/matrix_integer_sparse.pyx +1090 -0
  235. sage/matrix/matrix_rational_dense.cpython-313-aarch64-linux-gnu.so +0 -0
  236. sage/matrix/matrix_rational_dense.pxd +23 -0
  237. sage/matrix/matrix_rational_dense.pyx +2995 -0
  238. sage/matrix/matrix_rational_sparse.cpython-313-aarch64-linux-gnu.so +0 -0
  239. sage/matrix/matrix_rational_sparse.pxd +11 -0
  240. sage/matrix/matrix_rational_sparse.pyx +789 -0
  241. sage/matrix/misc_flint.cpython-313-aarch64-linux-gnu.so +0 -0
  242. sage/matrix/misc_flint.pyx +109 -0
  243. sage/modular/all__sagemath_flint.py +1 -0
  244. sage/modular/modform/all__sagemath_flint.py +1 -0
  245. sage/modular/modform/eis_series_cython.cpython-313-aarch64-linux-gnu.so +0 -0
  246. sage/modular/modform/eis_series_cython.pyx +226 -0
  247. sage/modular/modsym/all__sagemath_flint.py +1 -0
  248. sage/modular/modsym/apply.cpython-313-aarch64-linux-gnu.so +0 -0
  249. sage/modular/modsym/apply.pxd +6 -0
  250. sage/modular/modsym/apply.pyx +113 -0
  251. sage/modular/modsym/heilbronn.cpython-313-aarch64-linux-gnu.so +0 -0
  252. sage/modular/modsym/heilbronn.pyx +966 -0
  253. sage/modular/pollack_stevens/all__sagemath_flint.py +1 -0
  254. sage/modular/pollack_stevens/dist.cpython-313-aarch64-linux-gnu.so +0 -0
  255. sage/modular/pollack_stevens/dist.pxd +38 -0
  256. sage/modular/pollack_stevens/dist.pyx +1439 -0
  257. sage/quivers/algebra.py +691 -0
  258. sage/quivers/algebra_elements.cpython-313-aarch64-linux-gnu.so +0 -0
  259. sage/quivers/algebra_elements.pxd +97 -0
  260. sage/quivers/algebra_elements.pxi +1324 -0
  261. sage/quivers/algebra_elements.pyx +1424 -0
  262. sage/quivers/all.py +1 -0
  263. sage/quivers/ar_quiver.py +917 -0
  264. sage/quivers/homspace.py +640 -0
  265. sage/quivers/morphism.py +1282 -0
  266. sage/quivers/path_semigroup.py +1155 -0
  267. sage/quivers/paths.cpython-313-aarch64-linux-gnu.so +0 -0
  268. sage/quivers/paths.pxd +13 -0
  269. sage/quivers/paths.pyx +809 -0
  270. sage/quivers/representation.py +2975 -0
  271. sage/rings/all__sagemath_flint.py +37 -0
  272. sage/rings/cif.py +4 -0
  273. sage/rings/complex_arb.cpython-313-aarch64-linux-gnu.so +0 -0
  274. sage/rings/complex_arb.pxd +29 -0
  275. sage/rings/complex_arb.pyx +5176 -0
  276. sage/rings/complex_interval.cpython-313-aarch64-linux-gnu.so +0 -0
  277. sage/rings/complex_interval.pxd +30 -0
  278. sage/rings/complex_interval.pyx +2475 -0
  279. sage/rings/complex_interval_field.py +711 -0
  280. sage/rings/convert/all.py +1 -0
  281. sage/rings/convert/mpfi.cpython-313-aarch64-linux-gnu.so +0 -0
  282. sage/rings/convert/mpfi.pxd +6 -0
  283. sage/rings/convert/mpfi.pyx +576 -0
  284. sage/rings/factorint_flint.cpython-313-aarch64-linux-gnu.so +0 -0
  285. sage/rings/factorint_flint.pyx +99 -0
  286. sage/rings/fraction_field_FpT.cpython-313-aarch64-linux-gnu.so +0 -0
  287. sage/rings/fraction_field_FpT.pxd +28 -0
  288. sage/rings/fraction_field_FpT.pyx +2043 -0
  289. sage/rings/imaginary_unit.py +5 -0
  290. sage/rings/monomials.py +73 -0
  291. sage/rings/number_field/S_unit_solver.py +2870 -0
  292. sage/rings/number_field/all__sagemath_flint.py +7 -0
  293. sage/rings/number_field/bdd_height.py +664 -0
  294. sage/rings/number_field/class_group.py +762 -0
  295. sage/rings/number_field/galois_group.py +1307 -0
  296. sage/rings/number_field/homset.py +612 -0
  297. sage/rings/number_field/maps.py +687 -0
  298. sage/rings/number_field/morphism.py +272 -0
  299. sage/rings/number_field/number_field.py +12820 -0
  300. sage/rings/number_field/number_field_element.cpython-313-aarch64-linux-gnu.so +0 -0
  301. sage/rings/number_field/number_field_element.pxd +59 -0
  302. sage/rings/number_field/number_field_element.pyx +5735 -0
  303. sage/rings/number_field/number_field_element_quadratic.cpython-313-aarch64-linux-gnu.so +0 -0
  304. sage/rings/number_field/number_field_element_quadratic.pxd +34 -0
  305. sage/rings/number_field/number_field_element_quadratic.pyx +3185 -0
  306. sage/rings/number_field/number_field_ideal_rel.py +925 -0
  307. sage/rings/number_field/number_field_morphisms.cpython-313-aarch64-linux-gnu.so +0 -0
  308. sage/rings/number_field/number_field_morphisms.pyx +781 -0
  309. sage/rings/number_field/number_field_rel.py +2734 -0
  310. sage/rings/number_field/order.py +2981 -0
  311. sage/rings/number_field/order_ideal.py +804 -0
  312. sage/rings/number_field/selmer_group.py +715 -0
  313. sage/rings/number_field/small_primes_of_degree_one.py +242 -0
  314. sage/rings/number_field/splitting_field.py +606 -0
  315. sage/rings/number_field/structure.py +380 -0
  316. sage/rings/number_field/unit_group.py +721 -0
  317. sage/rings/padics/all__sagemath_flint.py +3 -0
  318. sage/rings/polynomial/all__sagemath_flint.py +1 -0
  319. sage/rings/polynomial/complex_roots.py +312 -0
  320. sage/rings/polynomial/evaluation_flint.cpython-313-aarch64-linux-gnu.so +0 -0
  321. sage/rings/polynomial/evaluation_flint.pxd +7 -0
  322. sage/rings/polynomial/evaluation_flint.pyx +68 -0
  323. sage/rings/polynomial/hilbert.cpython-313-aarch64-linux-gnu.so +0 -0
  324. sage/rings/polynomial/hilbert.pyx +602 -0
  325. sage/rings/polynomial/polynomial_complex_arb.cpython-313-aarch64-linux-gnu.so +0 -0
  326. sage/rings/polynomial/polynomial_complex_arb.pxd +7 -0
  327. sage/rings/polynomial/polynomial_complex_arb.pyx +963 -0
  328. sage/rings/polynomial/polynomial_integer_dense_flint.cpython-313-aarch64-linux-gnu.so +0 -0
  329. sage/rings/polynomial/polynomial_integer_dense_flint.pxd +13 -0
  330. sage/rings/polynomial/polynomial_integer_dense_flint.pyx +1881 -0
  331. sage/rings/polynomial/polynomial_number_field.cpython-313-aarch64-linux-gnu.so +0 -0
  332. sage/rings/polynomial/polynomial_number_field.pyx +345 -0
  333. sage/rings/polynomial/polynomial_rational_flint.cpython-313-aarch64-linux-gnu.so +0 -0
  334. sage/rings/polynomial/polynomial_rational_flint.pxd +20 -0
  335. sage/rings/polynomial/polynomial_rational_flint.pyx +2598 -0
  336. sage/rings/polynomial/polynomial_zmod_flint.cpython-313-aarch64-linux-gnu.so +0 -0
  337. sage/rings/polynomial/polynomial_zmod_flint.pxd +20 -0
  338. sage/rings/polynomial/polynomial_zmod_flint.pyx +1063 -0
  339. sage/rings/polynomial/real_roots.cpython-313-aarch64-linux-gnu.so +0 -0
  340. sage/rings/polynomial/real_roots.pxd +81 -0
  341. sage/rings/polynomial/real_roots.pyx +4704 -0
  342. sage/rings/polynomial/refine_root.cpython-313-aarch64-linux-gnu.so +0 -0
  343. sage/rings/polynomial/refine_root.pyx +142 -0
  344. sage/rings/polynomial/weil/all.py +4 -0
  345. sage/rings/polynomial/weil/power_sums.h +46 -0
  346. sage/rings/polynomial/weil/weil_polynomials.cpython-313-aarch64-linux-gnu.so +0 -0
  347. sage/rings/polynomial/weil/weil_polynomials.pyx +596 -0
  348. sage/rings/qqbar.py +9025 -0
  349. sage/rings/real_arb.cpython-313-aarch64-linux-gnu.so +0 -0
  350. sage/rings/real_arb.pxd +21 -0
  351. sage/rings/real_arb.pyx +4065 -0
  352. sage/rings/real_interval_absolute.cpython-313-aarch64-linux-gnu.so +0 -0
  353. sage/rings/real_interval_absolute.pyx +1073 -0
  354. sage/rings/real_mpfi.cpython-313-aarch64-linux-gnu.so +0 -0
  355. sage/rings/real_mpfi.pyx +5428 -0
  356. sage/schemes/all__sagemath_flint.py +1 -0
  357. sage/schemes/elliptic_curves/all__sagemath_flint.py +1 -0
  358. sage/schemes/elliptic_curves/descent_two_isogeny.cpython-313-aarch64-linux-gnu.so +0 -0
  359. sage/schemes/elliptic_curves/descent_two_isogeny.pyx +1387 -0
  360. sage/schemes/elliptic_curves/descent_two_isogeny_pari.pxd +5 -0
@@ -0,0 +1,4704 @@
1
+ # sage_setup: distribution = sagemath-flint
2
+ # sage.doctest: needs numpy sage.libs.linbox
3
+ """
4
+ Isolate Real Roots of Real Polynomials
5
+
6
+ AUTHOR:
7
+
8
+ - Carl Witty (2007-09-19): initial version
9
+
10
+ This is an implementation of real root isolation. That is, given a
11
+ polynomial with exact real coefficients, we compute isolating intervals
12
+ for the real roots of the polynomial. (Polynomials with
13
+ integer, rational, or algebraic real coefficients are supported.)
14
+
15
+ We convert the polynomials into the Bernstein basis, and then use
16
+ de Casteljau's algorithm and Descartes' rule of signs on the Bernstein
17
+ basis polynomial (using interval arithmetic) to locate the roots. The
18
+ algorithm is similar to that in "A Descartes Algorithm for Polynomials
19
+ with Bit-Stream Coefficients", by Eigenwillig, Kettner, Krandick, Mehlhorn,
20
+ Schmitt, and Wolpert, but has three crucial optimizations over the
21
+ algorithm in that paper:
22
+
23
+ - Precision reduction: at certain points in the computation, we discard the
24
+ low-order bits of the coefficients, widening the intervals.
25
+
26
+ - Degree reduction: at certain points in the computation, we find lower-degree
27
+ polynomials that are approximately equal to our high-degree polynomial over
28
+ the region of interest.
29
+
30
+ - When the intervals are too wide to continue (either because of a too-low
31
+ initial precision, or because of precision or degree reduction), and we need
32
+ to restart with higher precision, we recall which regions have already been
33
+ proven not to have any roots and do not examine them again.
34
+
35
+ The best description of the algorithms used (other than this source
36
+ code itself) is in the slides for my Sage Days 4 talk, currently available
37
+ from https://wiki.sagemath.org/days4schedule .
38
+ """
39
+
40
+ ################################################################################
41
+ # Copyright (C) 2007 Carl Witty <cwitty@newtonlabs.com>
42
+ #
43
+ # Distributed under the terms of the GNU General Public License (GPL)
44
+ #
45
+ # http://www.gnu.org/licenses/
46
+ ################################################################################
47
+
48
+ # TODO:
49
+ # These things would almost certainly improve the speed:
50
+ # * Use Anatole Ruslanov's register tiling versions of de Casteljau's
51
+ # algorithms when doing de Casteljau splitting at 1/2 in the integer case.
52
+ # * Use a register tiling version of de Casteljau's algorithm for the
53
+ # floating-point case...if you have n free FP registers (after allocating
54
+ # registers to hold r and 1-r) you should be able to do about n rows at
55
+ # once.
56
+ # * Use vectorized FP instructions for de Casteljau's algorithm.
57
+ # Using SSE2 to do 2 FP operations at once should be twice as fast.
58
+ # * Faster degree elevation
59
+ # Currently, when bernstein_expand expands from a degree-d1 to a
60
+ # degree-d2 polynomial, it does O(d2^2 - d1^2) operations. I
61
+ # have thought of (but not implemented) an approach that takes
62
+ # O(d1*d2) operations, which should be much faster when d1 is 30
63
+ # and d2 is 1000.
64
+ # Basically, the idea is to compute the d1 derivatives of the polynomial
65
+ # at x=0. This can be done exactly, in O(d1^2) operations. Then
66
+ # lift the d1'th derivative (a constant polynomial) to a polynomial of
67
+ # formal degree d2-d1 (trivial; the coefficients are just d2-d1+1 copies
68
+ # of the derivative). Then, compute the integral of that polynomial
69
+ # d1 times, using the computed derivatives to give the constant offset.
70
+ # (Computing the integral in Bernstein form involves divisions; these can
71
+ # be done ahead of time, to the derivatives at x=0.)
72
+ # The only tricky bit is tracking the error bounds and making sure you
73
+ # use appropriate precisions at various parts of the computation.
74
+
75
+ # These things are interesting ideas that may or may not help:
76
+ # * Partial degree reduction
77
+ # Build a new subclass of interval_bernstein_polynomial, which
78
+ # represents a polynomial as the sum of several
79
+ # interval_bernstein_polynomial_integer (of different degrees).
80
+ # Suppose you have a degree-1000 polynomial with 2000-bit coefficients.
81
+ # When you try degree reduction, you get a degree-30 polynomial with
82
+ # 2000-bit coefficients; but you get 300 bits of error.
83
+ # Instead of just using the degree-30 polynomial and accepting the
84
+ # loss of 300 bits of precision, you could represent the reduced polynomial
85
+ # as the sum of a degree-30 polynomial with 2000-bit coefficients and
86
+ # a degree-1000 polynomial with 300-bit coefficients. The combined
87
+ # polynomial should still be much cheaper to work with than the original.
88
+ # * Faster degree reduction
89
+ # Perhaps somebody clever can figure out a way to do degree reduction
90
+ # that doesn't involve matrix inversion, so that degree reduction can
91
+ # target degrees larger than 30.
92
+ # * Better heuristics
93
+ # ** Better degree reduction heuristics
94
+ # When should we degree reduce? What degrees should be targeted?
95
+ # ** Better precision reduction heuristics
96
+ # ** Better split point selection
97
+ # Currently we attempt to split at 1/2, and then at a random offset.
98
+ # We do not look at the current coefficients at all to try to select
99
+ # a good split point. Would it be worthwhile to do so? (For instance,
100
+ # it's a standard result that the polynomial in the region is bounded
101
+ # by the convex hull of the coefficients.)
102
+ # * Better initial transformation into Bernstein form
103
+ # If a polynomial has roots which are very close to 0, or very large,
104
+ # it may be better to rescale the roots (using a transformation like
105
+ # p -> p(1000*x)). This can be done as part of the initial transformation
106
+ # into Bernstein form.
107
+ # If a polynomial has some roots which are very close to 0, and also
108
+ # some roots which are very large, it might be better to isolate the roots
109
+ # in two groups.
110
+ # * More kinds of interval_bernstein_polynomial
111
+ # Currently we have arbitrary-precision GMP coefficients or double-precision
112
+ # floats. Would choices between these extremes help? (double-double?
113
+ # quad-double? fixed-precision multi-word integer arithmetic?)
114
+ # * Currently, some of our competitors are faster than this algorithm
115
+ # for polynomials that are "easy" in some way. (This algorithm
116
+ # seems to be vastly faster than everything else for "hard" polynomials.)
117
+ # Maybe there is a way to start out using another algorithm
118
+ # and then switch over to this algorithm once the polynomial
119
+ # is determined to be hard.
120
+ # * standard optimization
121
+ # There's probably some more to be gained by just running the profiler
122
+ # and optimizing individual functions. (To use more Cython features, for
123
+ # instance.)
124
+
125
+ # Extra features:
126
+ # * Specify a minimal island width: once islands are this narrow,
127
+ # stop even if roots are not isolated.
128
+ # * Do some sort of inexact version, for inexact input polynomials.
129
+ # (For example, given a polynomial with (non-point) interval coefficients,
130
+ # give a set of roots such that each root is guaranteed to be a root
131
+ # of some polynomial in the set represented by the interval polynomial.
132
+ # This may be vastly faster than the exact calculations carried out
133
+ # by this algorithm! Is it enough faster to be faster than, say,
134
+ # Pari's floating-point algorithms?)
135
+
136
+ from copy import copy
137
+ import time
138
+
139
+ from sage.rings.integer_ring import ZZ
140
+ from sage.rings.rational_field import QQ
141
+ from sage.rings.infinity import infinity
142
+ from sage.rings.qqbar import AA
143
+ from sage.rings.real_double import RDF
144
+ from sage.rings.real_mpfi import RealIntervalField, RIF
145
+ from sage.rings.real_mpfr import RR, RealField
146
+ from sage.arith.misc import binomial, factorial
147
+ from sage.misc.randstate import randstate
148
+ from sage.modules.free_module_element import free_module_element as vector
149
+ from sage.modules.free_module import FreeModule
150
+ from sage.matrix.matrix_space import MatrixSpace
151
+ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
152
+ from sage.misc.functional import numerator, denominator
153
+ from sage.misc.misc_c import prod
154
+
155
+ from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense
156
+ from sage.modules.vector_integer_dense cimport Vector_integer_dense
157
+ from sage.modules.vector_real_double_dense cimport Vector_real_double_dense
158
+ from sage.rings.integer cimport Integer
159
+ from sage.rings.real_mpfr cimport RealNumber
160
+
161
+ cimport numpy
162
+
163
+ from libc.math cimport fabs, sqrt, ldexp, frexp
164
+
165
+ from sage.libs.gmp.mpz cimport *
166
+ from sage.libs.gmp.mpq cimport *
167
+ from sage.libs.mpfr cimport *
168
+
169
+ cdef class interval_bernstein_polynomial:
170
+ r"""
171
+ An interval_bernstein_polynomial is an approximation to an exact
172
+ polynomial. This approximation is in the form of a Bernstein
173
+ polynomial (a polynomial given as coefficients over a Bernstein
174
+ basis) with interval coefficients.
175
+
176
+ The Bernstein basis of degree n over the region [a .. b] is the
177
+ set of polynomials
178
+
179
+ .. MATH::
180
+
181
+ \binom{n}{k} (x-a)^k (b-x)^{n-k} / (b-a)^n
182
+
183
+ for `0 \le k \le n`.
184
+
185
+ A degree-n interval Bernstein polynomial P with its region [a .. b] can
186
+ represent an exact polynomial p in two different ways: it can
187
+ "contain" the polynomial or it can "bound" the polynomial.
188
+
189
+ We say that P contains p if, when p is represented as a degree-n
190
+ Bernstein polynomial over [a .. b], its coefficients are contained
191
+ in the corresponding interval coefficients of P. For instance,
192
+ [0.9 .. 1.1]*x^2 (which is a degree-2 interval Bernstein polynomial
193
+ over [0 .. 1]) contains x^2.
194
+
195
+ We say that P bounds p if, for all a <= x <= b, there exists a
196
+ polynomial p' contained in P such that p(x) == p'(x). For instance,
197
+ [0 .. 1]*x is a degree-1 interval Bernstein polynomial which bounds
198
+ x^2 over [0 .. 1].
199
+
200
+ If P contains p, then P bounds p; but the converse is not necessarily
201
+ true. In particular, if n < m, it is possible for a degree-n interval
202
+ Bernstein polynomial to bound a degree-m polynomial; but it cannot
203
+ contain the polynomial.
204
+
205
+ In the case where P bounds p, we maintain extra information, the
206
+ "slope error". We say that P (over [a .. b]) bounds p with a
207
+ slope error of E (where E is an interval) if there is a polynomial
208
+ p' contained in P such that the derivative of (p - p') is bounded
209
+ by E in the range [a .. b]. If P bounds p with a slope error of 0
210
+ then P contains p.
211
+
212
+ (Note that "contains" and "bounds" are not standard terminology;
213
+ I just made them up.)
214
+
215
+ Interval Bernstein polynomials are useful in finding real roots
216
+ because of the following properties:
217
+
218
+ - Given an exact real polynomial p, we can compute an interval Bernstein
219
+ polynomial over an arbitrary region containing p.
220
+
221
+ - Given an interval Bernstein polynomial P over [a .. c], where a < b < c,
222
+ we can compute interval Bernstein polynomials P1 over [a .. b] and P2
223
+ over [b .. c], where P1 and P2 contain (or bound) all polynomials that P
224
+ contains (or bounds).
225
+
226
+ - Given a degree-n interval Bernstein polynomial P over [a .. b], and m <
227
+ n, we can compute a degree-m interval Bernstein polynomial P' over [a ..
228
+ b] that bounds all polynomials that P bounds.
229
+
230
+ - It is sometimes possible to prove that no polynomial bounded by P over [a
231
+ .. b] has any roots in [a .. b]. (Roughly, this is possible when no
232
+ polynomial contained by P has any complex roots near the line segment [a
233
+ .. b], where "near" is defined relative to the length b-a.)
234
+
235
+ - It is sometimes possible to prove that every polynomial bounded by P over
236
+ [a .. b] with slope error E has exactly one root in [a .. b]. (Roughly,
237
+ this is possible when every polynomial contained by P over [a .. b] has
238
+ exactly one root in [a .. b], there are no other complex roots near the
239
+ line segment [a .. b], and every polynomial contained in P has a
240
+ derivative which is bounded away from zero over [a .. b] by an amount
241
+ which is large relative to E.)
242
+
243
+ - Starting from a sufficiently precise interval Bernstein polynomial, it is
244
+ always possible to split it into polynomials which provably have 0 or 1
245
+ roots (as long as your original polynomial has no multiple real roots).
246
+
247
+ So a rough outline of a family of algorithms would be:
248
+
249
+ - Given a polynomial p, compute a region [a .. b] in which any real roots
250
+ must lie.
251
+ - Compute an interval Bernstein polynomial P containing p over [a .. b].
252
+ - Keep splitting P until you have isolated all the roots. Optionally,
253
+ reduce the degree or the precision of the interval Bernstein polynomials
254
+ at intermediate stages (to reduce computation time). If this seems not
255
+ to be working, go back and try again with higher precision.
256
+
257
+ Obviously, there are many details to be worked out to turn this
258
+ into a full algorithm, like:
259
+
260
+ - What initial precision is selected for computing P?
261
+ - How do you decide when to reduce the degree of intermediate polynomials?
262
+ - How do you decide when to reduce the precision of intermediate
263
+ polynomials?
264
+ - How do you decide where to split the interval Bernstein polynomial
265
+ regions?
266
+ - How do you decide when to give up and start over with higher precision?
267
+
268
+ Each set of answers to these questions gives a different algorithm
269
+ (potentially with very different performance characteristics), but all of
270
+ them can use this ``interval_bernstein_polynomial`` class as their basic
271
+ building block.
272
+
273
+ To save computation time, all coefficients in an
274
+ ``interval_bernstein_polynomial`` share the same interval width.
275
+ (There is one exception: when creating an ``interval_bernstein_polynomial``,
276
+ the first and last coefficients can be marked as "known positive"
277
+ or "known negative". This has some of the same effect as having
278
+ a (potentially) smaller interval width for these two coefficients,
279
+ although it does not affect de Casteljau splitting.)
280
+ To allow for widely varying coefficient magnitudes, all
281
+ coefficients in an interval_bernstein_polynomial are scaled
282
+ by `2^n` (where `n` may be positive, negative, or zero).
283
+
284
+ There are two representations for interval_bernstein_polynomials,
285
+ integer and floating-point. These are the two subclasses of
286
+ this class; ``interval_bernstein_polynomial`` itself is an abstract
287
+ class.
288
+
289
+ ``interval_bernstein_polynomial`` and its subclasses are not expected
290
+ to be used outside this file.
291
+ """
292
+
293
+ def variations(self):
294
+ """
295
+ Consider a polynomial (written in either the normal power basis
296
+ or the Bernstein basis). Take its list of coefficients, omitting
297
+ zeroes. Count the number of positions in the list where the
298
+ sign of one coefficient is opposite the sign of the next coefficient.
299
+
300
+ This count is the number of sign variations of the polynomial.
301
+ According to Descartes' rule of signs, the number of real
302
+ roots of the polynomial (counted with multiplicity) in a
303
+ certain interval is always less than or equal to the number of
304
+ sign variations, and the difference is always even. (If the
305
+ polynomial is written in the power basis, the region is the
306
+ positive reals; if the polynomial is written in the Bernstein
307
+ basis over a particular region, then we count roots in that region.)
308
+
309
+ In particular, a polynomial with no sign variations has no real
310
+ roots in the region, and a polynomial with one sign variation
311
+ has one real root in the region.
312
+
313
+ In an interval Bernstein polynomial, we do not necessarily
314
+ know the signs of the coefficients (if some of the coefficient
315
+ intervals contain zero), so the polynomials contained by
316
+ this interval polynomial may not all have the same number
317
+ of sign variations. However, we can compute a range of
318
+ possible numbers of sign variations.
319
+
320
+ This function returns the range, as a 2-tuple of integers.
321
+ """
322
+ return (self.min_variations, self.max_variations)
323
+
324
+ cdef void update_variations(self, interval_bernstein_polynomial bp1, interval_bernstein_polynomial bp2) noexcept:
325
+ """
326
+ Update the max_variations of ``bp1`` and ``bp2`` (which are assumed to
327
+ be the result of splitting this polynomial).
328
+
329
+ If we knew the number of variations of ``self``, ``bp1``, and ``bp2``
330
+ exactly, we would have
331
+ ``self.variations == bp1.variations + bp2.variations + 2*n``
332
+ for some nonnegative integer n. Thus, we can use our information
333
+ on min and max variations on ``self`` and ``bp1`` (or ``bp2``) to
334
+ refine the range on ``bp2`` (or ``bp1``).
335
+ """
336
+ if self.max_variations - bp1.min_variations < bp2.max_variations:
337
+ bp2.max_variations = self.max_variations - bp1.min_variations
338
+ if self.max_variations - bp2.min_variations < bp1.max_variations:
339
+ bp1.max_variations = self.max_variations - bp2.min_variations
340
+
341
+ def try_split(self, context ctx, logging_note):
342
+ """
343
+ Try doing a de Casteljau split of this polynomial at 1/2, resulting
344
+ in polynomials p1 and p2. If we see that the sign of this polynomial
345
+ is determined at 1/2, then return (p1, p2, 1/2); otherwise,
346
+ return None.
347
+
348
+ EXAMPLES::
349
+
350
+ sage: from sage.rings.polynomial.real_roots import *
351
+ sage: bp = mk_ibpi([50, 20, -90, -70, 200], error=5)
352
+ sage: bp1, bp2, _ = bp.try_split(mk_context(), None)
353
+ sage: bp1
354
+ <IBP: (50, 35, 0, -29, -31) + [0 .. 6) over [0 .. 1/2]>
355
+ sage: bp2
356
+ <IBP: (-31, -33, -8, 65, 200) + [0 .. 6) over [1/2 .. 1]>
357
+ sage: bp = mk_ibpf([0.5, 0.2, -0.9, -0.7, 0.99], neg_err=-0.1, pos_err=0.01)
358
+ sage: bp1, bp2, _ = bp.try_split(mk_context(), None)
359
+ sage: bp1
360
+ <IBP: (0.5, 0.35, 0.0, -0.2875, -0.369375) + [-0.10000000000000023 .. 0.010000000000000226] over [0 .. 1/2]>
361
+ sage: bp2
362
+ <IBP: (-0.369375, -0.45125, -0.3275, 0.14500000000000002, 0.99) + [-0.10000000000000023 .. 0.010000000000000226] over [1/2 .. 1]>
363
+ """
364
+ (p1, p2, ok) = self.de_casteljau(ctx, QQ_1_2)
365
+ ctx.dc_log_append(("half" + self._type_code(), self.scale_log2, self.bitsize, ok, logging_note))
366
+ if ok:
367
+ return (p1, p2, QQ_1_2)
368
+ return None
369
+
370
+ def try_rand_split(self, context ctx, logging_note):
371
+ """
372
+ Compute a random split point r (using the random number generator
373
+ embedded in ctx). We require 1/4 <= r < 3/4 (to ensure that
374
+ recursive algorithms make progress).
375
+
376
+ Then, try doing a de Casteljau split of this polynomial at r, resulting
377
+ in polynomials p1 and p2. If we see that the sign of this polynomial
378
+ is determined at r, then return (p1, p2, r); otherwise,
379
+ return None.
380
+
381
+ EXAMPLES::
382
+
383
+ sage: from sage.rings.polynomial.real_roots import *
384
+ sage: bp = mk_ibpi([50, 20, -90, -70, 200], error=5)
385
+ sage: bp1, bp2, _ = bp.try_rand_split(mk_context(), None)
386
+ sage: bp1
387
+ <IBP: (50, 29, -27, -56, -11) + [0 .. 6) over [0 .. 43/64]>
388
+ sage: bp2
389
+ <IBP: (-11, 10, 49, 111, 200) + [0 .. 6) over [43/64 .. 1]>
390
+ sage: bp1, bp2, _ = bp.try_rand_split(mk_context(seed=42), None)
391
+ sage: bp1
392
+ <IBP: (50, 32, -11, -41, -29) + [0 .. 6) over [0 .. 583/1024]>
393
+ sage: bp2
394
+ <IBP: (-29, -20, 13, 83, 200) + [0 .. 6) over [583/1024 .. 1]>
395
+ sage: bp = mk_ibpf([0.5, 0.2, -0.9, -0.7, 0.99], neg_err=-0.1, pos_err=0.01)
396
+ sage: bp1, bp2, _ = bp.try_rand_split(mk_context(), None)
397
+ sage: bp1 # rel tol
398
+ <IBP: (0.5, 0.2984375, -0.2642578125, -0.5511661529541015, -0.3145806974172592) + [-0.10000000000000069 .. 0.010000000000000677] over [0 .. 43/64]>
399
+ sage: bp2 # rel tol
400
+ <IBP: (-0.3145806974172592, -0.19903896331787108, 0.04135986328125002, 0.43546875, 0.99) + [-0.10000000000000069 .. 0.010000000000000677] over [43/64 .. 1]>
401
+ """
402
+
403
+ # We want a split point which is a dyadic rational (denominator
404
+ # is a power of 2), because that speeds up de_casteljau. We want
405
+ # a small denominator, because that helps us find simpler isolating
406
+ # intervals. However, if we require that our denominator be too
407
+ # small, then that might keep the algorithm from terminating;
408
+ # if the current polynomial has roots at (4/16, 5/16, ..., 12/16),
409
+ # and we pick our split points from that same set, then we will
410
+ # never find a split point with a determined sign. We avoid this
411
+ # problem by making sure we have more possible split points
412
+ # to choose from than our polynomial has roots.
413
+
414
+ # A different algorithm here might be more efficient.
415
+
416
+ div = 1024
417
+ while self.degree() >= (div // 4):
418
+ div = div * 2
419
+ qdiv = div // 4 # divides evenly since div = 1024*2^k
420
+ rand = Integer(ctx.random.randrange(qdiv, 3*qdiv)) / div
421
+ (p1, p2, ok) = self.de_casteljau(ctx, rand)
422
+ ctx.dc_log_append(("div" + self._type_code(), self.scale_log2, self.bitsize, rand, ok, logging_note))
423
+ if ok:
424
+ return (p1, p2, rand)
425
+ return None
426
+
427
+ cdef int degree(self) noexcept:
428
+ raise NotImplementedError()
429
+
430
+ def region(self):
431
+ return (self.lower, self.upper)
432
+
433
+ def region_width(self):
434
+ return (self.upper - self.lower)
435
+
436
+ dr_cache = {}
437
+
438
+ cdef class interval_bernstein_polynomial_integer(interval_bernstein_polynomial):
439
+ """
440
+ This is the subclass of :class:`interval_bernstein_polynomial` where
441
+ polynomial coefficients are represented using integers.
442
+
443
+ In this integer representation, each coefficient is represented by
444
+ a GMP arbitrary-precision integer A, and a (shared) interval width
445
+ E (which is a machine integer). These represent the coefficients
446
+ A*2^n <= c < (A+E)*2^n.
447
+
448
+ (Note that :func:`mk_ibpi is a simple helper` function for creating
449
+ elements of :class:`interval_bernstein_polynomial_integer` in doctests.)
450
+
451
+ EXAMPLES::
452
+
453
+ sage: from sage.rings.polynomial.real_roots import *
454
+ sage: bp = mk_ibpi([1, 2, 3], error=5); print(bp)
455
+ degree 2 IBP with 2-bit coefficients
456
+ sage: bp
457
+ <IBP: (1, 2, 3) + [0 .. 5)>
458
+ sage: bp.variations()
459
+ (0, 0)
460
+ sage: bp = mk_ibpi([-3, -1, 1, -1, -3, -1], lower=1, upper=5/4, usign=1, # needs sage.symbolic
461
+ ....: error=2, scale_log2=-3, level=2, slope_err=RIF(pi)); print(bp)
462
+ degree 5 IBP with 2-bit coefficients
463
+ sage: bp # needs sage.symbolic
464
+ <IBP: ((-3, -1, 1, -1, -3, -1) + [0 .. 2)) * 2^-3 over [1 .. 5/4]; usign 1;
465
+ level 2; slope_err 3.141592653589794?>
466
+ sage: bp.variations() # needs sage.symbolic
467
+ (3, 3)
468
+ """
469
+
470
+ def __init__(self, Vector_integer_dense coeffs, Rational lower, Rational upper, int lsign, int usign, int error, int scale_log2, int level, RealIntervalFieldElement slope_err):
471
+ """
472
+ Initialize an interval_bernstein_polynomial_integer.
473
+
474
+ INPUT:
475
+
476
+ - ``coeffs`` -- a coefficient vector for a polynomial in Bernstein form
477
+ - ``lower`` -- the lower bound of the region over which the Bernstein basis is defined
478
+ - ``upper`` -- the upper bound of the region over which the Bernstein basis is defined
479
+ - ``lsign`` -- the sign of the polynomial at lower, if known
480
+ - ``usign`` -- the sign of the polynomial at upper, if known
481
+ - ``error`` -- the maximum error in the Bernstein coefficients
482
+ - ``scale_log2`` -- the log2 of the scaling factor for the Bernstein coefficients
483
+ - ``level`` -- the number of times we have performed degree reduction to get this polynomial
484
+ - ``slope_err`` -- the maximum extra error in the derivative of this polynomial from degree reduction
485
+
486
+ EXAMPLES::
487
+
488
+ sage: from sage.rings.polynomial.real_roots import *
489
+ sage: bp = interval_bernstein_polynomial_integer(vector(ZZ, [50, -30, -10]), -3/7, 4/7, 0, -1, 17, 3, 2, RIF(10^-30))
490
+ sage: print(bp)
491
+ degree 2 IBP with 6-bit coefficients
492
+ sage: bp
493
+ <IBP: ((50, -30, -10) + [0 .. 17)) * 2^3 over [-3/7 .. 4/7]; usign -1; level 2; slope_err 1.0000000000000000?e-30>
494
+ """
495
+ assert len(coeffs) > 0
496
+ self.coeffs = coeffs
497
+ self.lower = lower
498
+ self.upper = upper
499
+ self.lsign = lsign
500
+ if self.lsign == 0:
501
+ if mpz_sgn(coeffs._entries[0]) > 0:
502
+ self.lsign = 1
503
+ if mpz_cmp_si(coeffs._entries[0], -error) <= 0:
504
+ self.lsign = -1
505
+ self.usign = usign
506
+ cdef int n = len(coeffs)
507
+ if self.usign == 0:
508
+ if mpz_sgn(coeffs._entries[n-1]) > 0:
509
+ self.usign = 1
510
+ if mpz_cmp_si(coeffs._entries[n-1], -error) <= 0:
511
+ self.usign = -1
512
+ self.error = error
513
+ self.scale_log2 = scale_log2
514
+ self.level = level
515
+ self.slope_err = slope_err
516
+ self._set_bitsize()
517
+ self._count_variations()
518
+ self.lft = None
519
+
520
+ def __repr__(self):
521
+ """
522
+ Reveal all the internals of this interval Bernstein polynomial.
523
+
524
+ EXAMPLES::
525
+
526
+ sage: from sage.rings.polynomial.real_roots import *
527
+ sage: bp = mk_ibpi([-11, 22, -33], upper=1/9, error=20, lsign=1)
528
+ sage: repr(bp)
529
+ '<IBP: (-11, 22, -33) + [0 .. 20) over [0 .. 1/9]; lsign 1>'
530
+ """
531
+ base = "%s + [0 .. %s)" % (self.coeffs, self.error)
532
+ if self.scale_log2 != 0:
533
+ base = "(%s) * 2^%d" % (base, self.scale_log2)
534
+ s = "<IBP: %s" % base
535
+ if self.lower != 0 or self.upper != 1:
536
+ s += " over [%s .. %s]" % (self.lower, self.upper)
537
+ if (mpz_sgn(self.coeffs._entries[0]) <= 0 and mpz_cmp_si(self.coeffs._entries[0], -self.error) > 0) and self.lsign != 0:
538
+ s += "; lsign %d" % self.lsign
539
+ cdef int n = len(self.coeffs)
540
+ if (mpz_sgn(self.coeffs._entries[n-1]) <= 0 and mpz_cmp_si(self.coeffs._entries[n-1], -self.error) > 0) and self.usign != 0:
541
+ s += "; usign %d" % self.usign
542
+ if self.level != 0:
543
+ s += "; level %d" % self.level
544
+ if not (self.slope_err == 0):
545
+ s += "; slope_err %s" % self.slope_err
546
+ return s + ">"
547
+
548
+ def __str__(self):
549
+ """
550
+ Return a short summary of this interval Bernstein polynomial.
551
+
552
+ EXAMPLES::
553
+
554
+ sage: from sage.rings.polynomial.real_roots import *
555
+ sage: bp = mk_ibpi([-11, 22, -33], upper=1/9, error=20, lsign=1)
556
+ sage: print(bp)
557
+ degree 2 IBP with 6-bit coefficients
558
+ sage: str(bp)
559
+ 'degree 2 IBP with 6-bit coefficients'
560
+ """
561
+ return "degree %d IBP with %d-bit coefficients" % (len(self.coeffs) - 1, self.bitsize)
562
+
563
+ def _type_code(self):
564
+ """
565
+ Classifies this as either an integer representation ('i') or a
566
+ floating-point representation ('f').
567
+ """
568
+ return 'i'
569
+
570
+ cdef void _set_bitsize(self) noexcept:
571
+ """
572
+ A private function that computes the maximum coefficient size
573
+ of this Bernstein polynomial (in bits).
574
+
575
+ EXAMPLES::
576
+
577
+ sage: from sage.rings.polynomial.real_roots import *
578
+ sage: print(mk_ibpi([2^12345]))
579
+ degree 0 IBP with 12346-bit coefficients
580
+ sage: print(mk_ibpi([2^12345 - 1]))
581
+ degree 0 IBP with 12345-bit coefficients
582
+ """
583
+ self.bitsize = max_bitsize_intvec(self.coeffs)
584
+
585
+ cdef void _count_variations(self) noexcept:
586
+ """
587
+ A private function that counts the number of sign variations in
588
+ this Bernstein polynomial. Since the coefficients are represented
589
+ with intervals, not exactly, we cannot necessarily compute the exact
590
+ number of sign variations; instead, we compute lower and upper
591
+ bounds on this number.
592
+
593
+ TESTS::
594
+
595
+ sage: from sage.rings.polynomial.real_roots import *
596
+ sage: mk_ibpi([-1, -2, -3], error=1).variations()
597
+ (0, 0)
598
+ sage: mk_ibpi([-1, -2, -3], error=2).variations()
599
+ (0, 2)
600
+ sage: mk_ibpi([-1, -2, -3], error=2, lsign=-1).variations()
601
+ (0, 2)
602
+ sage: mk_ibpi([-1, -2, -3], error=2, lsign=0).variations()
603
+ (0, 2)
604
+ sage: mk_ibpi([-1, -2, -3], error=2, lsign=1).variations()
605
+ (1, 1)
606
+ sage: mk_ibpi([-1, -2, -3], error=3).variations()
607
+ (0, 2)
608
+ sage: mk_ibpi([-1, -2, -3], error=3, lsign=-1).variations()
609
+ (0, 2)
610
+ sage: mk_ibpi([-1, -2, -3], error=3, lsign=1).variations()
611
+ (1, 1)
612
+ sage: mk_ibpi([-1, -2, -3], error=4).variations()
613
+ (0, 2)
614
+ sage: mk_ibpi([-1, -2, -3], error=4, lsign=-1, usign=1).variations()
615
+ (1, 1)
616
+ sage: mk_ibpi([-1, -2, -3], error=4, lsign=1, usign=-1).variations()
617
+ (1, 1)
618
+ """
619
+ cdef Vector_integer_dense c = self.coeffs
620
+
621
+ cdef int count_maybe_pos, count_maybe_neg
622
+ cdef int sign
623
+ cdef int count_definite = 0
624
+
625
+ cdef int n = len(c)
626
+
627
+ cdef int new_count_maybe_pos, new_count_maybe_neg
628
+
629
+ cdef int lower_sgn, upper_sgn
630
+
631
+ cdef int i
632
+
633
+ if self.lsign > 0:
634
+ count_maybe_pos = 0
635
+ count_maybe_neg = -1
636
+ sign = 1
637
+ elif self.lsign < 0:
638
+ count_maybe_pos = -1
639
+ count_maybe_neg = 0
640
+ sign = -1
641
+ else:
642
+ count_maybe_pos = 0
643
+ count_maybe_neg = 0
644
+ sign = 0
645
+
646
+ for i in range(1, n):
647
+ lower_sgn = mpz_sgn(c._entries[i])
648
+ upper_sgn = mpz_cmp_si(c._entries[i], -self.error)
649
+ new_count_maybe_pos = count_maybe_pos
650
+ new_count_maybe_neg = count_maybe_neg
651
+ if lower_sgn > 0:
652
+ if sign < 0:
653
+ count_definite = count_definite + 1
654
+ sign = 1
655
+ new_count_maybe_neg = -1
656
+ if upper_sgn <= 0:
657
+ if sign > 0:
658
+ count_definite = count_definite + 1
659
+ sign = -1
660
+ new_count_maybe_pos = -1
661
+ if upper_sgn >= 0 and count_maybe_neg + 1 > new_count_maybe_pos:
662
+ new_count_maybe_pos = count_maybe_neg + 1
663
+ if lower_sgn < 0 and count_maybe_pos + 1 > new_count_maybe_neg:
664
+ new_count_maybe_neg = count_maybe_pos + 1
665
+
666
+ count_maybe_pos = new_count_maybe_pos
667
+ count_maybe_neg = new_count_maybe_neg
668
+
669
+ if self.usign > 0 and sign < 0:
670
+ count_definite = count_definite + 1
671
+ if self.usign < 0 and sign > 0:
672
+ count_definite = count_definite + 1
673
+ self.min_variations = count_definite
674
+
675
+ if self.usign > 0:
676
+ self.max_variations = count_maybe_pos
677
+ elif self.usign < 0:
678
+ self.max_variations = count_maybe_neg
679
+ else:
680
+ self.max_variations = max(count_maybe_pos, count_maybe_neg)
681
+
682
+ cdef int degree(self) noexcept:
683
+ """
684
+ Return the (formal) degree of this polynomial.
685
+ """
686
+ return len(self.coeffs) - 1
687
+
688
+ def de_casteljau(self, context ctx, mid, msign=0):
689
+ """
690
+ Uses de Casteljau's algorithm to compute the representation
691
+ of this polynomial in a Bernstein basis over new regions.
692
+
693
+ INPUT:
694
+
695
+ - ``mid`` -- where to split the Bernstein basis region; 0 < mid < 1
696
+ - ``msign`` -- default 0 (unknown); the sign of this polynomial at mid
697
+
698
+ OUTPUT:
699
+
700
+ - ``bp1``, ``bp2`` -- the new interval Bernstein polynomials
701
+ - ``ok`` -- boolean; ``True`` if the sign of the original polynomial at
702
+ mid is known
703
+
704
+ EXAMPLES::
705
+
706
+ sage: from sage.rings.polynomial.real_roots import *
707
+ sage: bp = mk_ibpi([50, 20, -90, -70, 200], error=5)
708
+ sage: ctx = mk_context()
709
+ sage: bp1, bp2, ok = bp.de_casteljau(ctx, 1/2)
710
+ sage: bp1
711
+ <IBP: (50, 35, 0, -29, -31) + [0 .. 6) over [0 .. 1/2]>
712
+ sage: bp2
713
+ <IBP: (-31, -33, -8, 65, 200) + [0 .. 6) over [1/2 .. 1]>
714
+ sage: bp1, bp2, ok = bp.de_casteljau(ctx, 2/3)
715
+ sage: bp1
716
+ <IBP: (50, 30, -26, -55, -13) + [0 .. 6) over [0 .. 2/3]>
717
+ sage: bp2
718
+ <IBP: (-13, 8, 47, 110, 200) + [0 .. 6) over [2/3 .. 1]>
719
+ sage: bp1, bp2, ok = bp.de_casteljau(ctx, 7/39)
720
+ sage: bp1
721
+ <IBP: (50, 44, 36, 27, 17) + [0 .. 6) over [0 .. 7/39]>
722
+ sage: bp2
723
+ <IBP: (17, -26, -75, -22, 200) + [0 .. 6) over [7/39 .. 1]>
724
+ """
725
+ (c1_, c2_, err_inc) = de_casteljau_intvec(self.coeffs, self.bitsize, mid, ctx.wordsize == 32)
726
+ cdef Vector_integer_dense c1 = c1_
727
+ cdef Vector_integer_dense c2 = c2_
728
+
729
+ cdef int new_err = self.error + err_inc
730
+
731
+ cdef int sign = 0
732
+
733
+ if mpz_sgn(c2._entries[0]) > 0:
734
+ sign = 1
735
+ if mpz_cmp_si(c2._entries[0], -new_err) <= 0:
736
+ sign = -1
737
+
738
+ if msign == 0:
739
+ msign = sign
740
+ elif sign != 0:
741
+ assert msign == sign
742
+
743
+ cdef Rational absolute_mid = self.lower + mid * (self.upper - self.lower)
744
+
745
+ cdef interval_bernstein_polynomial_integer bp1, bp2
746
+ bp1 = interval_bernstein_polynomial_integer(c1, self.lower, absolute_mid, self.lsign, msign, new_err, self.scale_log2, self.level, self.slope_err)
747
+ bp2 = interval_bernstein_polynomial_integer(c2, absolute_mid, self.upper, msign, self.usign, new_err, self.scale_log2, self.level, self.slope_err)
748
+
749
+ if self.lft is not None:
750
+ (a, b, c, d) = self.lft
751
+ bp1.lft = (a * mid, b, c * mid, d)
752
+ bp2.lft = (a * (1-mid), b + a*mid, c * (1-mid), d + c*mid)
753
+
754
+ if msign != 0:
755
+ self.update_variations(bp1, bp2)
756
+
757
+ return (bp1, bp2, msign != 0)
758
+
759
+ def as_float(self):
760
+ """
761
+ Compute an interval_bernstein_polynomial_float which contains
762
+ (or bounds) all the polynomials this interval polynomial
763
+ contains (or bounds).
764
+
765
+ EXAMPLES::
766
+
767
+ sage: from sage.rings.polynomial.real_roots import *
768
+ sage: bp = mk_ibpi([50, 20, -90, -70, 200], error=5)
769
+ sage: print(bp.as_float())
770
+ degree 4 IBP with floating-point coefficients
771
+ sage: bp.as_float()
772
+ <IBP: ((0.1953125, 0.078125, -0.3515625, -0.2734375, 0.78125) + [-1.1275702593849246e-16 .. 0.01953125000000017]) * 2^8>
773
+ """
774
+ (fcoeffs, neg_err, pos_err, scale_log2_delta) = intvec_to_doublevec(self.coeffs, self.error)
775
+ cdef interval_bernstein_polynomial_float fbp = interval_bernstein_polynomial_float(fcoeffs, self.lower, self.upper, self.lsign, self.usign, neg_err, pos_err, self.scale_log2 + scale_log2_delta, self.level, self.slope_err)
776
+ fbp.min_variations = self.min_variations
777
+ fbp.max_variations = self.max_variations
778
+ return fbp
779
+
780
+ def get_msb_bit(self):
781
+ """
782
+ Return an approximation of the log2 of the maximum of the
783
+ absolute values of the coefficients, as an integer.
784
+ """
785
+ return self.scale_log2 + self.bitsize
786
+
787
+ def down_degree(self, context ctx, max_err, exp_err_shift):
788
+ """
789
+ Compute an interval_bernstein_polynomial_integer which bounds
790
+ all the polynomials this interval polynomial bounds, but is
791
+ of lesser degree.
792
+
793
+ During the computation, we find an "expected error"
794
+ expected_err, which is the error inherent in our approach
795
+ (this depends on the degrees involved, and is proportional
796
+ to the error of the current polynomial).
797
+
798
+ We require that the error of the new interval polynomial
799
+ be bounded both by max_err, and by expected_err << exp_err_shift.
800
+ If we find such a polynomial p, then we return a pair of p and some
801
+ debugging/logging information. Otherwise, we return the pair
802
+ (None, None).
803
+
804
+ If the resulting polynomial would have error more than 2^17,
805
+ then it is downscaled before returning.
806
+
807
+ EXAMPLES::
808
+
809
+ sage: from sage.rings.polynomial.real_roots import *
810
+ sage: bp = mk_ibpi([0, 100, 400, 903], error=2)
811
+ sage: ctx = mk_context()
812
+ sage: bp
813
+ <IBP: (0, 100, 400, 903) + [0 .. 2)>
814
+ sage: dbp, _ = bp.down_degree(ctx, 10, 32)
815
+ sage: dbp
816
+ <IBP: (-1, 148, 901) + [0 .. 4); level 1; slope_err 0.?e2>
817
+ """
818
+
819
+ # return (None, None)
820
+
821
+ degree = self.degree()
822
+
823
+ try:
824
+ (next, downmat, expected_err, (bdi, den)) = dr_cache[degree]
825
+ except KeyError:
826
+ precompute_degree_reduction_cache(degree)
827
+ (next, downmat, expected_err, (bdi, den)) = dr_cache[degree]
828
+
829
+ expected_err = expected_err * self.error
830
+ if expected_err > max_err:
831
+ return (None, ('$', self.scale_log2 + bitsize(expected_err)))
832
+
833
+ if (expected_err << exp_err_shift) < max_err:
834
+ max_err = (expected_err << exp_err_shift)
835
+
836
+ v0 = dprod_imatrow_vec(bdi, self.coeffs, 0) // den
837
+ # v0 = dprod_matrow_vec(downmat, self.coeffs, 0)
838
+ v0_err = abs(v0 - self.coeffs[0])
839
+ if v0_err > max_err:
840
+ return (None, ('>', self.scale_log2 + bitsize(v0_err)))
841
+ vn = dprod_imatrow_vec(bdi, self.coeffs, next) // den
842
+ # vn = dprod_matrow_vec(downmat, self.coeffs, next)
843
+ vn_err = abs(vn - self.coeffs[degree])
844
+ if vn_err > max_err:
845
+ return (None, ('>', self.scale_log2 + bitsize(vn_err)))
846
+ ribp = (ZZ**(next+1))(0)
847
+ ribp[0] = v0
848
+ ribp[next] = vn
849
+ for i in range(1, next):
850
+ ribp[i] = dprod_imatrow_vec(bdi, self.coeffs, i) // den
851
+
852
+ before = time.time()
853
+ (eribp, err_inc) = bernstein_expand(ribp, self.degree())
854
+ after = time.time()
855
+ (base_max, base_min) = min_max_delta_intvec(self.coeffs, eribp)
856
+ err_max = base_max + self.error
857
+ err_min = base_min - err_inc
858
+ for i in range(len(ribp)):
859
+ ribp[i] = ribp[i] + err_min
860
+ err = err_max - err_min
861
+
862
+ ctx.be_log_append((after - before, self.scale_log2, max_bitsize_intvec(ribp), err < max_err, err_max, err_min, err_inc, self.degree(), next, self.variations()))
863
+ if err < max_err:
864
+ rng = RIF(-2*err, 2*err)
865
+ rng = rng * self.degree()
866
+ width = self.region_width()
867
+ rng = rng / width
868
+ if self.scale_log2 >= 0:
869
+ rng = rng << self.scale_log2
870
+ else:
871
+ rng = rng >> (-self.scale_log2)
872
+ # slope_err could be smaller by actually computing
873
+ # the derivative of the error polynomial
874
+ slope_err = rng
875
+ lsb = self.scale_log2
876
+ if err <= expected_err:
877
+ indicator = '<'
878
+ else:
879
+ indicator = '='
880
+ if bitsize(err) > 17:
881
+ shift = bitsize(err) - 15
882
+ for i in range(len(ribp)):
883
+ ribp[i] = ribp[i] >> shift
884
+ max_err = max_err >> shift
885
+ err = -((-err) >> shift)
886
+ lsb = lsb + shift
887
+ # warning: lsign and usign might have changed, invalidate them to 0
888
+ ibp = interval_bernstein_polynomial_integer(ribp, self.lower, self.upper, 0, 0, err, lsb, self.level+1, self.slope_err + slope_err)
889
+
890
+ return (ibp, (indicator, lsb + bitsize(err)))
891
+ else:
892
+ return (None, ('=', self.scale_log2 + bitsize(err)))
893
+
894
+ def down_degree_iter(self, context ctx, max_scale):
895
+ """
896
+ Compute a degree-reduced version of this interval polynomial, by
897
+ iterating down_degree.
898
+
899
+ We stop when degree reduction would give a polynomial which is
900
+ too inaccurate, meaning that either we think the current polynomial
901
+ may have more roots in its region than the degree of the
902
+ reduced polynomial, or that the least significant accurate bit
903
+ in the result (on the absolute scale) would be larger than
904
+ 1 << max_scale.
905
+
906
+ EXAMPLES::
907
+
908
+ sage: from sage.rings.polynomial.real_roots import *
909
+ sage: bp = mk_ibpi([0, 100, 400, 903, 1600, 2500], error=2)
910
+ sage: ctx = mk_context()
911
+ sage: bp
912
+ <IBP: (0, 100, 400, 903, 1600, 2500) + [0 .. 2)>
913
+ sage: rbp = bp.down_degree_iter(ctx, 6)
914
+ sage: rbp
915
+ <IBP: (-4, 249, 2497) + [0 .. 9); level 2; slope_err 0.?e3>
916
+ """
917
+
918
+ cdef interval_bernstein_polynomial bp = self
919
+
920
+ while True:
921
+ next = degree_reduction_next_size(bp.degree())
922
+ if next is None:
923
+ return bp
924
+ if bp.variations()[0] > next:
925
+ return bp
926
+ (rbp, err_info) = bp.down_degree(ctx, Integer(1) << (max_scale - bp.scale_log2), 32)
927
+ ctx.dc_log_append(('down_degree', rbp is not None, err_info))
928
+ if rbp is None:
929
+ # global dd_count_no
930
+ # dd_count_no += 1
931
+ return bp
932
+ else:
933
+ # global dd_count_yes
934
+ # dd_count_yes += 1
935
+ bp = rbp
936
+
937
+ def downscale(self, bits):
938
+ """
939
+ Compute an interval_bernstein_polynomial_integer which
940
+ contains (or bounds) all the polynomials this interval
941
+ polynomial contains (or bounds), but uses
942
+ "bits" fewer bits.
943
+
944
+ EXAMPLES::
945
+
946
+ sage: from sage.rings.polynomial.real_roots import *
947
+ sage: bp = mk_ibpi([0, 100, 400, 903], error=2)
948
+ sage: bp.downscale(5)
949
+ <IBP: ((0, 3, 12, 28) + [0 .. 1)) * 2^5>
950
+ """
951
+ p = self.coeffs.__copy__()
952
+ for i in range(len(p)):
953
+ p[i] = p[i] >> bits
954
+ return interval_bernstein_polynomial_integer(p, self.lower, self.upper, self.lsign, self.usign, -((-self.error) >> bits), self.scale_log2 + bits, self.level, self.slope_err)
955
+
956
+ def slope_range(self):
957
+ """
958
+ Compute a bound on the derivative of this polynomial, over its region.
959
+
960
+ EXAMPLES::
961
+
962
+ sage: from sage.rings.polynomial.real_roots import *
963
+ sage: bp = mk_ibpi([0, 100, 400, 903], error=2)
964
+ sage: bp.slope_range().str(style='brackets')
965
+ '[294.00000000000000 .. 1515.0000000000000]'
966
+ """
967
+ width = self.region_width()
968
+ (min_diff, max_diff) = min_max_diff_intvec(self.coeffs)
969
+ rng = RIF(min_diff - self.error, max_diff + self.error)
970
+ rng = rng * (len(self.coeffs) - 1)
971
+ rng = rng / width
972
+ if self.scale_log2 >= 0:
973
+ rng = rng << self.scale_log2
974
+ else:
975
+ rng = rng >> (-self.scale_log2)
976
+ return rng
977
+
978
+
979
+ def mk_ibpi(coeffs, lower=0, upper=1, lsign=0, usign=0, error=1, scale_log2=0,
980
+ level=0, slope_err=RIF(0)):
981
+ """
982
+ A simple wrapper for creating interval_bernstein_polynomial_integer
983
+ objects with coercions, defaults, etc.
984
+
985
+ For use in doctests.
986
+
987
+ EXAMPLES::
988
+
989
+ sage: from sage.rings.polynomial.real_roots import *
990
+ sage: print(mk_ibpi([50, 20, -90, -70, 200], error=5))
991
+ degree 4 IBP with 8-bit coefficients
992
+ """
993
+ return interval_bernstein_polynomial_integer(vector(ZZ, coeffs), QQ(lower), QQ(upper), lsign, usign, error, scale_log2, level, slope_err)
994
+
995
+
996
+ def de_casteljau_intvec(Vector_integer_dense c, int c_bitsize, Rational x, int use_ints):
997
+ """
998
+ Given a polynomial in Bernstein form with integer coefficients
999
+ over the region [0 .. 1], and a split point x, use de Casteljau's
1000
+ algorithm to give polynomials in Bernstein form over [0 .. x] and
1001
+ [x .. 1].
1002
+
1003
+ This function will work for an arbitrary rational split point x, as
1004
+ long as 0 < x < 1; but it has specialized code paths that make
1005
+ some values of x faster than others. If x == a/(a + b),
1006
+ there are special efficient cases for a==1, b==1, a+b fits in a machine
1007
+ word, a+b is a power of 2, a fits in a machine word, b fits in
1008
+ a machine word. The most efficient case is x==1/2.
1009
+
1010
+ Given split points x == a/(a + b) and y == c/(c + d), where
1011
+ min(a, b) and min(c, d) fit in the same number of machine words
1012
+ and a+b and c+d are both powers of two, then x and y should be
1013
+ equally fast split points.
1014
+
1015
+ If use_ints is nonzero, then instead of checking whether numerators
1016
+ and denominators fit in machine words, we check whether they fit in
1017
+ ints (32 bits, even on 64-bit machines). This slows things down, but
1018
+ allows for identical results across machines.
1019
+
1020
+ INPUT:
1021
+
1022
+ - ``c`` -- vector of coefficients of polynomial in Bernstein form
1023
+ - ``c_bitsize`` -- approximate size of coefficients in c (in bits)
1024
+ - ``x`` -- rational splitting point; 0 < x < 1
1025
+
1026
+ OUTPUT:
1027
+
1028
+ - ``c1`` -- coefficients of polynomial over range [0 .. x]
1029
+ - ``c2`` -- coefficients of polynomial over range [x .. 1]
1030
+ - ``err_inc`` -- amount by which error intervals widened
1031
+
1032
+ EXAMPLES::
1033
+
1034
+ sage: from sage.rings.polynomial.real_roots import *
1035
+ sage: c = vector(ZZ, [1048576, 0, 0, 0, 0, 0])
1036
+ sage: de_casteljau_intvec(c, 20, 1/2, 1)
1037
+ ((1048576, 524288, 262144, 131072, 65536, 32768), (32768, 0, 0, 0, 0, 0), 1)
1038
+ sage: de_casteljau_intvec(c, 20, 1/3, 1)
1039
+ ((1048576, 699050, 466033, 310689, 207126, 138084), (138084, 0, 0, 0, 0, 0), 1)
1040
+ sage: de_casteljau_intvec(c, 20, 7/22, 1)
1041
+ ((1048576, 714938, 487457, 332357, 226607, 154505), (154505, 0, 0, 0, 0, 0), 1)
1042
+ """
1043
+ vs = c.parent()
1044
+
1045
+ cdef Vector_integer_dense c1, c2, den_powers
1046
+
1047
+ c1 = Vector_integer_dense(vs, 0)
1048
+ c2 = c.__copy__()
1049
+
1050
+ cdef int n = len(c)
1051
+
1052
+ cdef int i, j
1053
+
1054
+ cdef mpz_t num, den, diff, tmp, tmp2
1055
+
1056
+ cdef unsigned long num_ui, den_ui, diff_ui
1057
+ cdef int num_fits_ui, den_fits_ui, diff_fits_ui
1058
+ cdef int den_is_pow2, den_log2
1059
+ cdef int num_less_diff
1060
+
1061
+ cdef int max_den_power
1062
+
1063
+ # We want to compute (diff*a + num*b)/den. This costs
1064
+ # 2*mul, 1*div, 1*add/sub.
1065
+ # We see below a way to trade a multiplication for a subtraction,
1066
+ # for a cost of 1*mul, 1*div, 2*add/sub.
1067
+ # Another possibility is to postpone divisions, for a cost of
1068
+ # 2*mul, 1/6*div, 1*add/sub. Clearly, this is worthwhile if
1069
+ # 5/6*div + 1*add/sub > 1*mul. This is very likely true whenever
1070
+ # the denominator is not a power of 2 (so that you have to do
1071
+ # real divisions, instead of shifts), and might be true in other cases.
1072
+
1073
+ # If one of the multiplications is by 1, then the costs become:
1074
+ # straightforward: 1*mul, 1*div, 1*add/sub
1075
+ # trade mul->sub: 1*div, 2*add/sub
1076
+ # postpone division: 1*mul, 1/6*div, 1*add/sub
1077
+ # for the same result.
1078
+
1079
+ # If both multiplications are by 1, then the costs are:
1080
+ # straightforward: 1*div, 1*add/sub
1081
+ # trade mul->sub: 1*div, 2*add/sub
1082
+ # postpone division: 1/6*div, 1*add/sub
1083
+ # with postpone division being the obvious winner.
1084
+
1085
+ # For now, we use "postpone division" whenever the denominator fits
1086
+ # in an unsigned long. This is not going to be drastically bad,
1087
+ # even when dividing by a power of two. For full generality,
1088
+ # it would also be important to use "postpone division" for
1089
+ # non-power-of-two denominators that do not fit in an unsigned long;
1090
+ # however, the current calling code essentially never does that,
1091
+ # so we'll stick with simpler code here.
1092
+
1093
+ mpz_init(num)
1094
+ mpz_init(den)
1095
+ mpz_init(diff)
1096
+ mpz_init(tmp)
1097
+ mpz_init(tmp2)
1098
+
1099
+ mpq_get_num(num, x.value)
1100
+ mpq_get_den(den, x.value)
1101
+ mpz_sub(diff, den, num)
1102
+
1103
+ if use_ints:
1104
+ den_fits_ui = mpz_fits_uint_p(den)
1105
+ num_fits_ui = mpz_fits_uint_p(num)
1106
+ diff_fits_ui = mpz_fits_uint_p(diff)
1107
+ else:
1108
+ den_fits_ui = mpz_fits_ulong_p(den)
1109
+ num_fits_ui = mpz_fits_ulong_p(num)
1110
+ diff_fits_ui = mpz_fits_ulong_p(diff)
1111
+
1112
+ if den_fits_ui:
1113
+ den_ui = mpz_get_ui(den)
1114
+ if num_fits_ui:
1115
+ num_ui = mpz_get_ui(num)
1116
+ if diff_fits_ui:
1117
+ diff_ui = mpz_get_ui(diff)
1118
+
1119
+ mpz_sub_ui(tmp, den, 1)
1120
+ mpz_and(tmp, tmp, den)
1121
+ den_is_pow2 = (mpz_sgn(tmp) == 0)
1122
+ if den_is_pow2:
1123
+ den_log2 = mpz_sizeinbase(den, 2) - 1
1124
+
1125
+ cdef int max_den_bits = c_bitsize / 2
1126
+ if max_den_bits < 100:
1127
+ max_den_bits = 100
1128
+ # These settings are slower than the above on laguerre(1000), but that's
1129
+ # the only experiment I've done so far... more testing is needed.
1130
+ # cdef int max_den_bits = 3 * c_bitsize / 2
1131
+ # if max_den_bits < 100: max_den_bits = 300
1132
+
1133
+ cdef int cur_den_steps = 0
1134
+
1135
+ cdef int ndivs = 0
1136
+
1137
+ if den_fits_ui:
1138
+ den_powers = FreeModule(ZZ, len(c)+1)(0)
1139
+ mpz_set_ui(den_powers._entries[0], 1)
1140
+ max_den_power = 1
1141
+ for i in range(1, n + 1):
1142
+ mpz_mul_ui(den_powers._entries[i], den_powers._entries[i-1], den_ui)
1143
+ if mpz_sizeinbase(den_powers._entries[i], 2) < max_den_bits:
1144
+ max_den_power = i
1145
+ else:
1146
+ break
1147
+
1148
+ for i in range(n):
1149
+ mpz_set(c1._entries[i], c2._entries[0])
1150
+ if den_ui == 2:
1151
+ # x == 1/2
1152
+ for j in range(n-i-1):
1153
+ mpz_add(c2._entries[j], c2._entries[j], c2._entries[j+1])
1154
+ else:
1155
+ for j in range(n-i-1):
1156
+ if diff_ui != 1:
1157
+ mpz_mul_ui(c2._entries[j], c2._entries[j], diff_ui)
1158
+ if num_ui == 1:
1159
+ mpz_add(c2._entries[j], c2._entries[j], c2._entries[j+1])
1160
+ else:
1161
+ mpz_addmul_ui(c2._entries[j], c2._entries[j+1], num_ui)
1162
+ cur_den_steps = cur_den_steps + 1
1163
+ if cur_den_steps == max_den_power or i == n-1:
1164
+ if den_is_pow2:
1165
+ for j from 1 <= j < cur_den_steps:
1166
+ mpz_fdiv_q_2exp(c1._entries[i-cur_den_steps+j+1],
1167
+ c1._entries[i-cur_den_steps+j+1],
1168
+ j*den_log2)
1169
+ mpz_fdiv_q_2exp(c2._entries[n-i+cur_den_steps-j-2],
1170
+ c2._entries[n-i+cur_den_steps-j-2],
1171
+ j*den_log2)
1172
+ for j from 0 <= j < n-i-1:
1173
+ mpz_fdiv_q_2exp(c2._entries[j], c2._entries[j],
1174
+ cur_den_steps*den_log2)
1175
+ else:
1176
+ for j from 1 <= j < cur_den_steps:
1177
+ mpz_fdiv_q(c1._entries[i-cur_den_steps+j+1],
1178
+ c1._entries[i-cur_den_steps+j+1],
1179
+ den_powers._entries[j])
1180
+ mpz_fdiv_q(c2._entries[n-i+cur_den_steps-j-2],
1181
+ c2._entries[n-i+cur_den_steps-j-2],
1182
+ den_powers._entries[j])
1183
+ for j from 0 <= j < n-i-1:
1184
+ mpz_fdiv_q(c2._entries[j], c2._entries[j],
1185
+ den_powers._entries[cur_den_steps])
1186
+ cur_den_steps = 0
1187
+ ndivs = ndivs+1
1188
+ else:
1189
+ # We want to compute (diff*a + num*b)/den, where
1190
+ # a == c2._entries[j] and b == c2._entries[j+1].
1191
+ # The result goes in c2._entries[j]. Since den == diff + num,
1192
+ # this is equal to a + num*(b-a)/den or diff*(a-b)/den + b.
1193
+ # If num<diff, we compute the former, otherwise the latter.
1194
+
1195
+ num_less_diff = (mpz_cmp(num, diff) < 0)
1196
+
1197
+ ndivs = n-1
1198
+
1199
+ for i in range(n):
1200
+ mpz_set(c1._entries[i], c2._entries[0])
1201
+ for j in range(n-i-1):
1202
+ if num_less_diff:
1203
+ mpz_sub(tmp, c2._entries[j+1], c2._entries[j])
1204
+ if num_fits_ui and num_ui == 1:
1205
+ if den_is_pow2:
1206
+ mpz_fdiv_q_2exp(tmp2, tmp, den_log2)
1207
+ elif den_fits_ui:
1208
+ mpz_fdiv_q_ui(tmp2, tmp, den_ui)
1209
+ else:
1210
+ mpz_fdiv_q(tmp2, tmp, den)
1211
+ mpz_add(c2._entries[j], c2._entries[j], tmp2)
1212
+ else:
1213
+ if num_fits_ui:
1214
+ mpz_mul_ui(tmp2, tmp, num_ui)
1215
+ else:
1216
+ mpz_mul(tmp2, tmp, num)
1217
+ if den_is_pow2:
1218
+ mpz_fdiv_q_2exp(tmp, tmp2, den_log2)
1219
+ elif den_fits_ui:
1220
+ mpz_fdiv_q_ui(tmp, tmp2, den_ui)
1221
+ else:
1222
+ mpz_fdiv_q(tmp, tmp2, den)
1223
+ mpz_add(c2._entries[j], c2._entries[j], tmp)
1224
+ else:
1225
+ mpz_sub(c2._entries[j], c2._entries[j], c2._entries[j+1])
1226
+ if diff_fits_ui:
1227
+ if diff_ui == 1:
1228
+ mpz_set(tmp, c2._entries[j])
1229
+ else:
1230
+ mpz_mul_ui(tmp, c2._entries[j], diff_ui)
1231
+ else:
1232
+ mpz_mul(tmp, c2._entries[j], diff)
1233
+ if den_is_pow2:
1234
+ mpz_fdiv_q_2exp(c2._entries[j], tmp, den_log2)
1235
+ elif den_fits_ui:
1236
+ mpz_fdiv_q_ui(c2._entries[j], tmp, den_ui)
1237
+ else:
1238
+ mpz_fdiv_q(c2._entries[j], tmp, den)
1239
+ mpz_add(c2._entries[j], c2._entries[j], c2._entries[j+1])
1240
+
1241
+ mpz_clear(num)
1242
+ mpz_clear(den)
1243
+ mpz_clear(diff)
1244
+ mpz_clear(tmp)
1245
+ mpz_clear(tmp2)
1246
+
1247
+ return (c1, c2, ndivs)
1248
+
1249
+ # An ULP is a "unit in the last place"; it is the (varying) unit for
1250
+ # how much adjacent floating-point numbers differ from each other.
1251
+ # A half-ULP is half this amount; it is the maximum rounding error
1252
+ # in the basic operations (+, -, *, /) in a correctly-operating IEEE
1253
+ # floating-point unit.
1254
+ # (Note that by default, the x86 does not use IEEE double precision;
1255
+ # instead, it uses extra precision, which can (counterintuitively)
1256
+ # actually give worse double-precision results in some rare cases.
1257
+ # To avoid this, we change the x86 floating-point unit into true
1258
+ # double-precision mode in places where it matters; that is, in
1259
+ # functions that add, subtract, multiply, or divide floating-point numbers.
1260
+ # Functions whose floating-point operations are limited to negation
1261
+ # and comparison do not require special treatment, since those operations
1262
+ # give the same results in double-precision or extended precision.)
1263
+
1264
+
1265
+ # This is the value of a half-ULP for numbers in the range 0.5 <= x < 1.
1266
+ # This is actually slightly more than a half-ULP because of possible
1267
+ # double-rounding on x86 PCs.
1268
+ cdef double half_ulp = ldexp(1.0 * 65/64, -54)
1269
+
1270
+
1271
+ def intvec_to_doublevec(Vector_integer_dense b, long err):
1272
+ r"""
1273
+ Given a vector of integers A = [a1, ..., an], and an integer
1274
+ error bound E, returns a vector of floating-point numbers
1275
+ B = [b1, ..., bn], lower and upper error bounds F1 and F2, and
1276
+ a scaling factor d, such that
1277
+
1278
+ .. MATH::
1279
+
1280
+ (bk + F1) * 2^d \le ak
1281
+
1282
+ and
1283
+
1284
+ .. MATH::
1285
+
1286
+ ak + E \le (bk + F2) * 2^d
1287
+
1288
+ If bj is the element of B with largest absolute value, then
1289
+ 0.5 <= abs(bj) < 1.0 .
1290
+
1291
+ EXAMPLES::
1292
+
1293
+ sage: from sage.rings.polynomial.real_roots import *
1294
+ sage: intvec_to_doublevec(vector(ZZ, [1, 2, 3, 4, 5]), 3)
1295
+ ((0.125, 0.25, 0.375, 0.5, 0.625), -1.1275702593849246e-16, 0.37500000000000017, 3)
1296
+ """
1297
+ vs = FreeModule(RDF, len(b))
1298
+
1299
+ cdef Vector_real_double_dense db = vs(0)
1300
+ cdef numpy.ndarray[double, ndim=1] dbv = db._vector_numpy
1301
+
1302
+ cdef long max_exp = -10000
1303
+ cdef long cur_exp
1304
+
1305
+ cdef int i
1306
+
1307
+ for i in range(len(b)):
1308
+ mpz_get_d_2exp(&cur_exp, b._entries[i])
1309
+ if cur_exp > max_exp:
1310
+ max_exp = cur_exp
1311
+
1312
+ cdef int delta = -max_exp
1313
+ cdef double d
1314
+ cdef int new_exp
1315
+
1316
+ for i in range(len(b)):
1317
+ d = mpz_get_d_2exp(&cur_exp, b._entries[i])
1318
+ # 0.5 <= d < 1; b._entries[i] ~= d*2^cur_exp
1319
+ new_exp = cur_exp + delta
1320
+ if new_exp >= -100:
1321
+ dbv[i] = ldexp(d, new_exp)
1322
+ # db[i] = ldexp(d, new_exp)
1323
+
1324
+ # The true value can be off by an ulp because mpz_get_d_2exp truncates.
1325
+ # (If we created a version of mpz_get_d_2exp that rounded instead,
1326
+ # we could do a little better.)
1327
+ # The third half_ulp in the positive direction is to compensate for
1328
+ # possible bad rounding when adding ldexp(err, delta).
1329
+
1330
+ cdef double low_err = -2*half_ulp
1331
+ cdef double high_err = 3*half_ulp + ldexp(err, delta)
1332
+ # fpu_fix_end(&cwf)
1333
+ return (db, low_err, high_err, -delta)
1334
+
1335
+
1336
+ cdef class interval_bernstein_polynomial_float(interval_bernstein_polynomial):
1337
+ """
1338
+ This is the subclass of :class:`interval_bernstein_polynomial` where
1339
+ polynomial coefficients are represented using floating-point numbers.
1340
+
1341
+ In the floating-point representation, each coefficient is represented
1342
+ as an IEEE double-precision float A, and the (shared) lower and
1343
+ upper interval widths E1 and E2. These represent the coefficients
1344
+ (A+E1)*2^n <= c <= (A+E2)*2^n.
1345
+
1346
+ Note that we always have E1 <= 0 <= E2. Also, each floating-point
1347
+ coefficient has absolute value less than one.
1348
+
1349
+ (Note that :func:`mk_ibpf` is a simple helper function for creating
1350
+ elements of :class:`interval_bernstein_polynomial_float` in doctests.)
1351
+
1352
+ EXAMPLES::
1353
+
1354
+ sage: from sage.rings.polynomial.real_roots import *
1355
+ sage: bp = mk_ibpf([0.1, 0.2, 0.3], pos_err=0.5); print(bp)
1356
+ degree 2 IBP with floating-point coefficients
1357
+ sage: bp
1358
+ <IBP: (0.1, 0.2, 0.3) + [0.0 .. 0.5]>
1359
+ sage: bp.variations()
1360
+ (0, 0)
1361
+ sage: bp = mk_ibpf([-0.3, -0.1, 0.1, -0.1, -0.3, -0.1], # needs sage.symbolic
1362
+ ....: lower=1, upper=5/4, usign=1, pos_err=0.2,
1363
+ ....: scale_log2=-3, level=2, slope_err=RIF(pi)); print(bp)
1364
+ degree 5 IBP with floating-point coefficients
1365
+ sage: bp # needs sage.symbolic
1366
+ <IBP: ((-0.3, -0.1, 0.1, -0.1, -0.3, -0.1) + [0.0 .. 0.2]) * 2^-3
1367
+ over [1 .. 5/4]; usign 1; level 2; slope_err 3.141592653589794?>
1368
+ sage: bp.variations() # needs sage.symbolic
1369
+ (3, 3)
1370
+ """
1371
+
1372
+ def __init__(self, Vector_real_double_dense coeffs, Rational lower, Rational upper, int lsign, int usign, double neg_err, double pos_err, int scale_log2, int level, RealIntervalFieldElement slope_err):
1373
+ """
1374
+ Initialize an interval_bernstein_polynomial_float.
1375
+
1376
+ INPUT:
1377
+
1378
+ - ``coeffs`` -- a coefficient vector for a polynomial in Bernstein form
1379
+ (all coefficients must have absolute value less than one)
1380
+ - ``lower`` -- the lower bound of the region over which the Bernstein basis
1381
+ is defined
1382
+ - ``upper`` -- the upper bound of the region over which the Bernstein basis
1383
+ is defined
1384
+ - ``lsign`` -- the sign of the polynomial at lower, if known
1385
+ - ``usign`` -- the sign of the polynomial at upper, if known
1386
+ - ``neg_err`` -- the minimum error in the Bernstein coefficients
1387
+ - ``pos_err`` -- the maximum error in the Bernstein coefficients (so a
1388
+ Bernstein coefficient x really represents the range [neg_err+x ..
1389
+ pos_err+x]
1390
+ - ``scale_log2`` -- the log2 of the scaling factor for the Bernstein
1391
+ coefficients
1392
+ - ``level`` -- the number of times we have performed degree reduction to
1393
+ get this polynomial
1394
+ - ``slope_err`` -- the maximum extra error in the derivative of this
1395
+ polynomial from degree reduction
1396
+
1397
+ EXAMPLES::
1398
+
1399
+ sage: from sage.rings.polynomial.real_roots import *
1400
+ sage: bp = interval_bernstein_polynomial_float(vector(RDF, [0.50, -0.30, -0.10]), -3/7, 4/7, 0, -1, -0.02, 0.17, 3, 2, RIF(10^-30))
1401
+ sage: print(bp)
1402
+ degree 2 IBP with floating-point coefficients
1403
+ sage: bp
1404
+ <IBP: ((0.5, -0.3, -0.1) + [-0.02 .. 0.17]) * 2^3 over [-3/7 .. 4/7]; usign -1; level 2; slope_err 1.0000000000000000?e-30>
1405
+ """
1406
+ assert len(coeffs) > 0
1407
+ cdef numpy.ndarray[double, ndim=1] coeffs_data = coeffs._vector_numpy
1408
+ self.coeffs = coeffs
1409
+ self.lower = lower
1410
+ self.upper = upper
1411
+ self.lsign = lsign
1412
+ if self.lsign == 0:
1413
+ if coeffs_data[0] > -neg_err:
1414
+ self.lsign = 1
1415
+ if coeffs_data[0] < -pos_err:
1416
+ self.lsign = -1
1417
+ self.usign = usign
1418
+ cdef int n = len(coeffs)
1419
+ if self.usign == 0:
1420
+ if coeffs_data[n-1] > -neg_err:
1421
+ self.usign = 1
1422
+ if coeffs_data[n-1] < -pos_err:
1423
+ self.usign = -1
1424
+ self.neg_err = neg_err
1425
+ self.pos_err = pos_err
1426
+ self.scale_log2 = scale_log2
1427
+ self.level = level
1428
+ self.slope_err = slope_err
1429
+ self._count_variations()
1430
+ max_abs = max_abs_doublevec(coeffs)
1431
+ cdef int exp
1432
+ frexp(max_abs, &exp)
1433
+ self.bitsize = exp + 53
1434
+ self.lft = None
1435
+
1436
+ def __repr__(self):
1437
+ """
1438
+ Reveal all the internals of this interval Bernstein polynomial.
1439
+
1440
+ EXAMPLES::
1441
+
1442
+ sage: from sage.rings.polynomial.real_roots import *
1443
+ sage: bp = mk_ibpf([-0.11, 0.22, -0.33], upper=1/9, neg_err=-0.3, pos_err=0.1, lsign=1)
1444
+ sage: repr(bp)
1445
+ '<IBP: (-0.11, 0.22, -0.33) + [-0.3 .. 0.1] over [0 .. 1/9]>'
1446
+ """
1447
+ base = "%s + [%r .. %r]" % (self.coeffs, self.neg_err, self.pos_err)
1448
+ if self.scale_log2 != 0:
1449
+ base = "(%s) * 2^%d" % (base, self.scale_log2)
1450
+ s = "<IBP: %s" % base
1451
+ if self.lower != 0 or self.upper != 1:
1452
+ s += " over [%s .. %s]" % (self.lower, self.upper)
1453
+ if self.coeffs.get_unsafe(0) <= -self.neg_err and self.coeffs.get_unsafe(0) >= -self.pos_err and self.lsign != 0:
1454
+ s += "; lsign %d" % self.lsign
1455
+ cdef int n = len(self.coeffs)
1456
+ if self.coeffs.get_unsafe(n-1) <= -self.neg_err and self.coeffs.get_unsafe(n-1) >= -self.pos_err and self.usign != 0:
1457
+ s += "; usign %d" % self.usign
1458
+ if self.level != 0:
1459
+ s += "; level %d" % self.level
1460
+ if self.slope_err != 0:
1461
+ s += "; slope_err %s" % self.slope_err
1462
+ return s + ">"
1463
+
1464
+ def __str__(self):
1465
+ """
1466
+ Return a short summary of this interval Bernstein polynomial.
1467
+
1468
+ EXAMPLES::
1469
+
1470
+ sage: from sage.rings.polynomial.real_roots import *
1471
+ sage: bp = mk_ibpf([-0.11, 0.22, -0.33], upper=1/9, neg_err=-0.1, pos_err=0.2, lsign=1)
1472
+ sage: print(bp)
1473
+ degree 2 IBP with floating-point coefficients
1474
+ sage: str(bp)
1475
+ 'degree 2 IBP with floating-point coefficients'
1476
+ """
1477
+ return "degree %d IBP with floating-point coefficients" % (len(self.coeffs) - 1)
1478
+
1479
+ def _type_code(self):
1480
+ """
1481
+ Classifies this as either an integer representation ('i') or a
1482
+ floating-point representation ('f').
1483
+ """
1484
+ return 'f'
1485
+
1486
+ cdef void _count_variations(self) noexcept:
1487
+ """
1488
+ A private function that counts the number of sign variations in
1489
+ this Bernstein polynomial. Since the coefficients are represented
1490
+ with intervals, not exactly, we cannot necessarily compute the exact
1491
+ number of sign variations; instead, we compute lower and upper
1492
+ bounds on this number.
1493
+ """
1494
+ cdef numpy.ndarray[double, ndim=1] cd = self.coeffs._vector_numpy
1495
+
1496
+ cdef int count_maybe_pos
1497
+ cdef int count_maybe_neg
1498
+ cdef int sign
1499
+ cdef int count_definite = 0
1500
+
1501
+ cdef int n = len(self.coeffs)
1502
+
1503
+ cdef int new_count_maybe_pos, new_count_maybe_neg
1504
+
1505
+ cdef int i
1506
+
1507
+ cdef double val
1508
+
1509
+ if self.lsign > 0:
1510
+ count_maybe_pos = 0
1511
+ count_maybe_neg = -1
1512
+ sign = 1
1513
+ elif self.lsign < 0:
1514
+ count_maybe_pos = -1
1515
+ count_maybe_neg = 0
1516
+ sign = -1
1517
+ else:
1518
+ count_maybe_pos = 0
1519
+ count_maybe_neg = 0
1520
+ sign = 0
1521
+
1522
+ for i in range(1, n):
1523
+ new_count_maybe_pos = count_maybe_pos
1524
+ new_count_maybe_neg = count_maybe_neg
1525
+ val = cd[i]
1526
+ if val > -self.neg_err:
1527
+ if sign < 0:
1528
+ count_definite = count_definite + 1
1529
+ sign = 1
1530
+ new_count_maybe_neg = -1
1531
+ if val < -self.pos_err:
1532
+ if sign > 0:
1533
+ count_definite = count_definite + 1
1534
+ sign = -1
1535
+ new_count_maybe_pos = -1
1536
+ if val > -self.pos_err and count_maybe_neg + 1 > new_count_maybe_pos:
1537
+ new_count_maybe_pos = count_maybe_neg + 1
1538
+ if val < -self.neg_err and count_maybe_pos + 1 > new_count_maybe_neg:
1539
+ new_count_maybe_neg = count_maybe_pos + 1
1540
+
1541
+ count_maybe_pos = new_count_maybe_pos
1542
+ count_maybe_neg = new_count_maybe_neg
1543
+
1544
+ if self.usign > 0 and sign < 0:
1545
+ count_definite = count_definite + 1
1546
+ if self.usign < 0 and sign > 0:
1547
+ count_definite = count_definite + 1
1548
+ self.min_variations = count_definite
1549
+
1550
+ if self.usign > 0:
1551
+ self.max_variations = count_maybe_pos
1552
+ elif self.usign < 0:
1553
+ self.max_variations = count_maybe_neg
1554
+ else:
1555
+ self.max_variations = max(count_maybe_pos, count_maybe_neg)
1556
+
1557
+ cdef int degree(self) noexcept:
1558
+ """
1559
+ Return the (formal) degree of this polynomial.
1560
+ """
1561
+ return len(self.coeffs) - 1
1562
+
1563
+ def de_casteljau(self, context ctx, mid, msign=0):
1564
+ """
1565
+ Uses de Casteljau's algorithm to compute the representation
1566
+ of this polynomial in a Bernstein basis over new regions.
1567
+
1568
+ INPUT:
1569
+
1570
+ - ``mid`` -- where to split the Bernstein basis region; ``0 < mid < 1``
1571
+ - ``msign`` -- default 0 (unknown); the sign of this polynomial at ``mid``
1572
+
1573
+ OUTPUT:
1574
+
1575
+ - ``bp1``, ``bp2`` -- the new interval Bernstein polynomials
1576
+ - ``ok`` -- boolean; ``True`` if the sign of the original polynomial at
1577
+ ``mid`` is known
1578
+
1579
+ EXAMPLES::
1580
+
1581
+ sage: from sage.rings.polynomial.real_roots import *
1582
+ sage: ctx = mk_context()
1583
+ sage: bp = mk_ibpf([0.5, 0.2, -0.9, -0.7, 0.99], neg_err=-0.1, pos_err=0.01)
1584
+ sage: bp1, bp2, ok = bp.de_casteljau(ctx, 1/2)
1585
+ sage: bp1
1586
+ <IBP: (0.5, 0.35, 0.0, -0.2875, -0.369375) + [-0.10000000000000023 .. 0.010000000000000226] over [0 .. 1/2]>
1587
+ sage: bp2
1588
+ <IBP: (-0.369375, -0.45125, -0.3275, 0.14500000000000002, 0.99) + [-0.10000000000000023 .. 0.010000000000000226] over [1/2 .. 1]>
1589
+ sage: bp1, bp2, ok = bp.de_casteljau(ctx, 2/3)
1590
+ sage: bp1 # rel tol 2e-16
1591
+ <IBP: (0.5, 0.30000000000000004, -0.2555555555555555, -0.5444444444444444, -0.32172839506172846) + [-0.10000000000000069 .. 0.010000000000000677] over [0 .. 2/3]>
1592
+ sage: bp2 # rel tol 3e-15
1593
+ <IBP: (-0.32172839506172846, -0.21037037037037046, 0.028888888888888797, 0.4266666666666666, 0.99) + [-0.10000000000000069 .. 0.010000000000000677] over [2/3 .. 1]>
1594
+ sage: bp1, bp2, ok = bp.de_casteljau(ctx, 7/39)
1595
+ sage: bp1 # rel tol
1596
+ <IBP: (0.5, 0.4461538461538461, 0.36653517422748183, 0.27328680523946786, 0.1765692706232836) + [-0.10000000000000069 .. 0.010000000000000677] over [0 .. 7/39]>
1597
+ sage: bp2 # rel tol
1598
+ <IBP: (0.1765692706232836, -0.26556803047927313, -0.7802038132807364, -0.3966666666666666, 0.99) + [-0.10000000000000069 .. 0.010000000000000677] over [7/39 .. 1]>
1599
+ """
1600
+ (c1_, c2_, err_inc) = de_casteljau_doublevec(self.coeffs, mid)
1601
+ cdef Vector_real_double_dense c1 = c1_
1602
+ cdef Vector_real_double_dense c2 = c2_
1603
+ cdef numpy.ndarray[double, ndim=1] c2data = c2._vector_numpy
1604
+ cdef int sign = 0
1605
+
1606
+ if c2data[0] > -self.neg_err:
1607
+ sign = 1
1608
+ if c2data[0] < -self.pos_err:
1609
+ sign = -1
1610
+
1611
+ if msign == 0:
1612
+ msign = sign
1613
+ elif sign != 0:
1614
+ assert msign == sign
1615
+
1616
+ # As long as new_neg and new_pos have
1617
+ # magnitudes less than 0.5, these computations
1618
+ # are exact. This will be the case for any sensible
1619
+ # usage of this class.
1620
+ cdef double new_neg = self.neg_err - half_ulp * err_inc
1621
+ cdef double new_pos = self.pos_err + half_ulp * err_inc
1622
+
1623
+ if not (-0.5 <= new_neg <= 0 <= new_pos <= 0.5):
1624
+ # Give up on this computation...it's horribly inaccurate anyway.
1625
+ msign = 0
1626
+
1627
+ cdef Rational absolute_mid = self.lower + mid * (self.upper - self.lower)
1628
+
1629
+ cdef interval_bernstein_polynomial_float bp1, bp2
1630
+ bp1 = interval_bernstein_polynomial_float(c1, self.lower, absolute_mid, self.lsign, msign, new_neg, new_pos, self.scale_log2, self.level, self.slope_err)
1631
+ bp2 = interval_bernstein_polynomial_float(c2, absolute_mid, self.upper, msign, self.usign, new_neg, new_pos, self.scale_log2, self.level, self.slope_err)
1632
+
1633
+ if self.lft is not None:
1634
+ (a, b, c, d) = self.lft
1635
+ bp1.lft = (a * mid, b, c * mid, d)
1636
+ bp2.lft = (a * (1-mid), b + a*mid, c * (1-mid), d + c*mid)
1637
+
1638
+ if msign != 0:
1639
+ self.update_variations(bp1, bp2)
1640
+
1641
+ return (bp1, bp2, msign != 0)
1642
+
1643
+ def as_float(self):
1644
+ return self
1645
+
1646
+ def get_msb_bit(self):
1647
+ """
1648
+ Return an approximation of the log2 of the maximum of the
1649
+ absolute values of the coefficients, as an integer.
1650
+ """
1651
+ return self.scale_log2 - 53 + self.bitsize
1652
+
1653
+ def slope_range(self):
1654
+ """
1655
+ Compute a bound on the derivative of this polynomial, over its region.
1656
+
1657
+ EXAMPLES::
1658
+
1659
+ sage: from sage.rings.polynomial.real_roots import *
1660
+ sage: bp = mk_ibpf([0.5, 0.2, -0.9, -0.7, 0.99], neg_err=-0.1, pos_err=0.01)
1661
+ sage: bp.slope_range().str(style='brackets')
1662
+ '[-4.8400000000000017 .. 7.2000000000000011]'
1663
+ """
1664
+ width = self.region_width()
1665
+ (min_diff, max_diff) = min_max_diff_doublevec(self.coeffs)
1666
+ err = self.pos_err - self.neg_err
1667
+ # 2 half_ulp's because subtracting two numbers with absolute values
1668
+ # in (-1 .. 1) can give a number in (-2 .. 2), and the subtraction
1669
+ # can have an error of up to half an ulp in that range, which
1670
+ # is 2 half ulps for (-1 .. 1).
1671
+ rng = RIF(min_diff - err - 2*half_ulp, max_diff + err + 2*half_ulp)
1672
+ rng = rng * (len(self.coeffs) - 1)
1673
+ rng = rng / width
1674
+ if self.scale_log2 >= 0:
1675
+ rng = rng << self.scale_log2
1676
+ else:
1677
+ rng = rng >> (-self.scale_log2)
1678
+
1679
+ # fpu_fix_end(&cwf)
1680
+
1681
+ return rng
1682
+
1683
+
1684
+ def mk_ibpf(coeffs, lower=0, upper=1, lsign=0, usign=0, neg_err=0, pos_err=0,
1685
+ scale_log2=0, level=0, slope_err=RIF(0)):
1686
+ """
1687
+ A simple wrapper for creating :class:`interval_bernstein_polynomial_float`
1688
+ objects with coercions, defaults, etc.
1689
+
1690
+ For use in doctests.
1691
+
1692
+ EXAMPLES::
1693
+
1694
+ sage: from sage.rings.polynomial.real_roots import *
1695
+ sage: print(mk_ibpf([0.5, 0.2, -0.9, -0.7, 0.99], pos_err=0.1, neg_err=-0.01))
1696
+ degree 4 IBP with floating-point coefficients
1697
+ """
1698
+ return interval_bernstein_polynomial_float(vector(RDF, coeffs), QQ(lower), QQ(upper), lsign, usign, neg_err, pos_err, scale_log2, level, slope_err)
1699
+
1700
+
1701
+ cdef Rational QQ_1_2 = QQ((1, 2))
1702
+ cdef Rational QQ_1_32 = QQ((1, 32))
1703
+ cdef Rational QQ_31_32 = QQ((31, 32))
1704
+ cdef Rational zero_QQ = QQ.zero()
1705
+ cdef Rational one_QQ = QQ.one()
1706
+ cdef Integer zero_ZZ = ZZ.zero()
1707
+ cdef Integer one_ZZ = ZZ.one()
1708
+ cdef Integer ZZ_2_31 = ZZ(2) ** 31
1709
+ cdef Integer ZZ_2_32 = ZZ(2) ** 32
1710
+ cdef RealIntervalFieldElement zero_RIF = RIF(0)
1711
+
1712
+
1713
+ def de_casteljau_doublevec(Vector_real_double_dense c, Rational x):
1714
+ """
1715
+ Given a polynomial in Bernstein form with floating-point coefficients
1716
+ over the region [0 .. 1], and a split point x, use de Casteljau's
1717
+ algorithm to give polynomials in Bernstein form over [0 .. x] and
1718
+ [x .. 1].
1719
+
1720
+ This function will work for an arbitrary rational split point x, as
1721
+ long as 0 < x < 1; but it has a specialized code path for x==1/2.
1722
+
1723
+ INPUT:
1724
+
1725
+ - ``c`` -- vector of coefficients of polynomial in Bernstein form
1726
+ - ``x`` -- rational splitting point; 0 < x < 1
1727
+
1728
+ OUTPUT:
1729
+
1730
+ - ``c1`` -- coefficients of polynomial over range [0 .. x]
1731
+ - ``c2`` -- coefficients of polynomial over range [x .. 1]
1732
+ - ``err_inc`` -- number of half-ulps by which error intervals widened
1733
+
1734
+ EXAMPLES::
1735
+
1736
+ sage: from sage.rings.polynomial.real_roots import *
1737
+ sage: c = vector(RDF, [0.7, 0, 0, 0, 0, 0])
1738
+ sage: de_casteljau_doublevec(c, 1/2)
1739
+ ((0.7, 0.35, 0.175, 0.0875, 0.04375, 0.021875), (0.021875, 0.0, 0.0, 0.0, 0.0, 0.0), 5)
1740
+ sage: de_casteljau_doublevec(c, 1/3) # rel tol
1741
+ ((0.7, 0.4666666666666667, 0.31111111111111117, 0.20740740740740746, 0.13827160493827165, 0.09218106995884777), (0.09218106995884777, 0.0, 0.0, 0.0, 0.0, 0.0), 15)
1742
+ sage: de_casteljau_doublevec(c, 7/22) # rel tol
1743
+ ((0.7, 0.4772727272727273, 0.3254132231404959, 0.22187265214124724, 0.15127680827812312, 0.10314327837144759), (0.10314327837144759, 0.0, 0.0, 0.0, 0.0, 0.0), 15)
1744
+ """
1745
+ vs = c.parent()
1746
+
1747
+ cdef Vector_real_double_dense c1, c2
1748
+
1749
+ c1 = Vector_real_double_dense(vs, 0)
1750
+ c2 = c.__copy__()
1751
+
1752
+ cdef numpy.ndarray[double, ndim=1] c1d = c1._vector_numpy
1753
+ cdef numpy.ndarray[double, ndim=1] c2d = c2._vector_numpy
1754
+
1755
+ cdef double half = 0.5
1756
+
1757
+ cdef int n = len(c)
1758
+ cdef int i, j
1759
+
1760
+ cdef double rx, rnx
1761
+
1762
+ cdef int extra_err
1763
+
1764
+ if x == QQ_1_2:
1765
+ for i in range(n):
1766
+ c1d[i] = c2d[0]
1767
+ for j in range(n-i-1):
1768
+ c2d[j] = (c2d[j] + c2d[j+1]) * half
1769
+
1770
+ # The following code lets us avoid O(n^2) floating-point multiplications
1771
+ # in favor of O(n) calls to ldexp(). In one experiment, though, it seems
1772
+ # to actually slow down the code by about 10%. (On an Intel Core 2 Duo
1773
+ # in 32-bit mode, on the test chebyt2(200).)
1774
+ # cur_den_steps = cur_den_steps + 1
1775
+ # if cur_den_steps == 1020 or i == n-1:
1776
+ # for j from 1 <= j < cur_den_steps:
1777
+ # c1d[i-cur_den_steps+j+1] = ldexp(c1d[i-cur_den_steps+j+1], -j)
1778
+ # c2d[n-i+cur_den_steps-j-2] = ldexp(c2d[n-i+cur_den_steps-j-2], -j)
1779
+ # for j from 0 <= j < n-i-1:
1780
+ # c2d[j] = ldexp(c2d[j], -cur_den_steps)
1781
+
1782
+ extra_err = n-1
1783
+ else:
1784
+ rx = x
1785
+ rnx = 1-rx
1786
+ for i from 0 <= i < n:
1787
+ c1d[i] = c2d[0]
1788
+ for j from 0 <= j < n-i-1:
1789
+ c2d[j] = (c2d[j]*rnx + c2d[j+1]*rx)
1790
+
1791
+ extra_err = 3*(n-1)
1792
+
1793
+ # fpu_fix_end(&cwf)
1794
+
1795
+ return (c1, c2, extra_err)
1796
+
1797
+
1798
+ def max_abs_doublevec(Vector_real_double_dense c):
1799
+ """
1800
+ Given a floating-point vector, return the maximum of the
1801
+ absolute values of its elements.
1802
+
1803
+ EXAMPLES::
1804
+
1805
+ sage: from sage.rings.polynomial.real_roots import *
1806
+ sage: max_abs_doublevec(vector(RDF, [0.1, -0.767, 0.3, 0.693]))
1807
+ 0.767
1808
+ """
1809
+ cdef numpy.ndarray[double, ndim=1] cd = c._vector_numpy
1810
+
1811
+ cdef double m = 0
1812
+ cdef double a
1813
+
1814
+ for i in range(len(c)):
1815
+ a = fabs(cd[i])
1816
+ if a > m:
1817
+ m = a
1818
+
1819
+ return m
1820
+
1821
+
1822
+ def wordsize_rational(a, b, wordsize):
1823
+ """
1824
+ Given rationals a and b, select a de Casteljau split point r between
1825
+ a and b.
1826
+
1827
+ An attempt is made to select an efficient split point
1828
+ (according to the criteria mentioned in the documentation
1829
+ for de_casteljau_intvec), with a bias towards split points near a.
1830
+
1831
+ In full detail:
1832
+
1833
+ This takes as input two rationals, a and b, such that 0<=a<=1, 0<=b<=1,
1834
+ and a!=b. This returns rational r, such that a<=r<=b or b<=r<=a.
1835
+ The denominator of r is a power of 2. Let m be min(r, 1-r),
1836
+ nm be numerator(m), and dml be log2(denominator(m)). The return value
1837
+ r is taken from the first of the following classes to have any
1838
+ members between a and b (except that if a <= 1/8, or 7/8 <= a, then
1839
+ class 2 is preferred to class 1).
1840
+
1841
+ 1. dml < wordsize
1842
+ 2. bitsize(nm) <= wordsize
1843
+ 3. bitsize(nm) <= 2*wordsize
1844
+ 4. bitsize(nm) <= 3*wordsize
1845
+
1846
+ ...
1847
+
1848
+ k. bitsize(nm) <= (k-1)*wordsize
1849
+
1850
+ From the first class to have members between a and b, r is chosen
1851
+ as the element of the class which is closest to a.
1852
+
1853
+ EXAMPLES::
1854
+
1855
+ sage: from sage.rings.polynomial.real_roots import *
1856
+ sage: wordsize_rational(1/5, 1/7, 32)
1857
+ 429496729/2147483648
1858
+ sage: wordsize_rational(1/7, 1/5, 32)
1859
+ 306783379/2147483648
1860
+ sage: wordsize_rational(1/5, 1/7, 64)
1861
+ 1844674407370955161/9223372036854775808
1862
+ sage: wordsize_rational(1/7, 1/5, 64)
1863
+ 658812288346769701/4611686018427387904
1864
+ sage: wordsize_rational(1/17, 1/19, 32)
1865
+ 252645135/4294967296
1866
+ sage: wordsize_rational(1/17, 1/19, 64)
1867
+ 1085102592571150095/18446744073709551616
1868
+ sage: wordsize_rational(1/1234567890, 1/1234567891, 32)
1869
+ 933866427/1152921504606846976
1870
+ sage: wordsize_rational(1/1234567890, 1/1234567891, 64)
1871
+ 4010925763784056541/4951760157141521099596496896
1872
+ """
1873
+
1874
+ # assert 0 <= a <= 1
1875
+
1876
+ swap_01 = False
1877
+ if b <= a:
1878
+ a = one_QQ-a
1879
+ b = one_QQ-b
1880
+ swap_01 = True
1881
+ sub_1 = False
1882
+ if a > QQ_1_2:
1883
+ a = a-one_QQ
1884
+ b = b-one_QQ
1885
+ sub_1 = True
1886
+
1887
+ cur_size = wordsize
1888
+ # fld = RealField(cur_size, rnd='RNDU')
1889
+ fld = get_realfield_rndu(cur_size)
1890
+ cdef RealNumber rf
1891
+ while True:
1892
+ rf = fld(a)
1893
+ if cur_size == wordsize:
1894
+ assert mpfr_number_p(rf.value)
1895
+ exp = mpfr_get_exp(rf.value)
1896
+ if rf <= -(fld(-b)):
1897
+ if exp <= -3:
1898
+ break
1899
+ # rf2 = RealField(cur_size + exp - 1, rnd='RNDU')(a)
1900
+ fld2 = get_realfield_rndu(cur_size + exp - 1)
1901
+ rf2 = fld2(a)
1902
+ if rf2 <= -(fld2(-b)):
1903
+ rf = rf2
1904
+ break
1905
+ if rf <= -(fld(-b)):
1906
+ break
1907
+ cur_size = cur_size + wordsize
1908
+ fld = RealField(cur_size, rnd='RNDU')
1909
+
1910
+ r = rf.exact_rational()
1911
+ if sub_1:
1912
+ r = r + one_QQ
1913
+ if swap_01:
1914
+ r = one_QQ - r
1915
+ # assert 0 <= r <= 1
1916
+ return r
1917
+
1918
+
1919
+ def relative_bounds(a, b):
1920
+ """
1921
+ INPUT:
1922
+
1923
+ - ``(al, ah)`` -- pair of rationals
1924
+ - ``(bl, bh)`` -- pair of rationals
1925
+
1926
+ OUTPUT:
1927
+
1928
+ - ``(cl, ch)`` -- pair of rationals
1929
+
1930
+ Computes the linear transformation that maps (al, ah) to (0, 1);
1931
+ then applies this transformation to (bl, bh) and returns the result.
1932
+
1933
+ EXAMPLES::
1934
+
1935
+ sage: from sage.rings.polynomial.real_roots import *
1936
+ sage: relative_bounds((1/7, 1/4), (1/6, 1/5))
1937
+ (2/9, 8/15)
1938
+ """
1939
+ (al, ah) = a
1940
+ (bl, bh) = b
1941
+ width = ah - al
1942
+ return ((bl - al) / width, (bh - al) / width)
1943
+
1944
+
1945
+ cdef int bitsize(Integer a) noexcept:
1946
+ """
1947
+ Compute the number of bits required to write a given integer
1948
+ (the sign is ignored).
1949
+
1950
+ EXAMPLES::
1951
+
1952
+ sage: from sage.rings.polynomial.real_roots import *
1953
+ sage: bitsize_doctest(0)
1954
+ 1
1955
+ sage: bitsize_doctest(1)
1956
+ 1
1957
+ sage: bitsize_doctest(2)
1958
+ 2
1959
+ sage: bitsize_doctest(-2)
1960
+ 2
1961
+ sage: bitsize_doctest(65535)
1962
+ 16
1963
+ sage: bitsize_doctest(65536)
1964
+ 17
1965
+ """
1966
+ return int(mpz_sizeinbase(a.value, 2))
1967
+
1968
+
1969
+ def bitsize_doctest(n):
1970
+ return bitsize(n)
1971
+
1972
+
1973
+ def degree_reduction_next_size(n):
1974
+ """
1975
+ Given n (a polynomial degree), returns either a smaller integer or ``None``.
1976
+ This defines the sequence of degrees followed by our degree reduction
1977
+ implementation.
1978
+
1979
+ EXAMPLES::
1980
+
1981
+ sage: from sage.rings.polynomial.real_roots import *
1982
+ sage: degree_reduction_next_size(1000)
1983
+ 30
1984
+ sage: degree_reduction_next_size(20)
1985
+ 15
1986
+ sage: degree_reduction_next_size(3)
1987
+ 2
1988
+ sage: degree_reduction_next_size(2) is None
1989
+ True
1990
+ """
1991
+
1992
+ # Virtually any descending sequence would be "correct" here; no
1993
+ # testing has been done to see if another sequence would be better.
1994
+
1995
+ # Constraints: must return None for n <= 2; degree reduction to
1996
+ # degrees > 30 may be very, very slow. (Part of reducing from
1997
+ # degree n to degree k is computing the exact inverse of a k by k
1998
+ # rational matrix. Fortunately, this matrix depends only on
1999
+ # n and k, so the inverted matrix can be cached; but still,
2000
+ # computing the exact inverse of a k by k matrix seems infeasible
2001
+ # for k much larger than 30.)
2002
+
2003
+ if n <= 2:
2004
+ return None
2005
+ next = n * 3 // 4
2006
+ if next > 30:
2007
+ next = 30
2008
+ return next
2009
+
2010
+
2011
+ def precompute_degree_reduction_cache(n):
2012
+ """
2013
+ Compute and cache the matrices used for degree reduction, starting
2014
+ from degree n.
2015
+
2016
+ EXAMPLES::
2017
+
2018
+ sage: from sage.rings.polynomial.real_roots import *
2019
+ sage: precompute_degree_reduction_cache(5)
2020
+ sage: dr_cache[5]
2021
+ (
2022
+ [121/126 8/63 -1/9 -2/63 11/126 -2/63]
2023
+ [ -3/7 37/42 16/21 1/21 -3/7 1/6]
2024
+ [ 1/6 -3/7 1/21 16/21 37/42 -3/7]
2025
+ 3, [ -2/63 11/126 -2/63 -1/9 8/63 121/126], 2,
2026
+ <BLANKLINE>
2027
+ ([121 16 -14 -4 11 -4]
2028
+ [-54 111 96 6 -54 21]
2029
+ [ 21 -54 6 96 111 -54]
2030
+ [ -4 11 -4 -14 16 121], 126)
2031
+ )
2032
+ """
2033
+ while True:
2034
+ if n in dr_cache:
2035
+ return
2036
+ next = degree_reduction_next_size(n)
2037
+ if next is None:
2038
+ dr_cache[n] = (None, None, 0)
2039
+ return
2040
+
2041
+ # We can compute a degree n -> degree k reduction by looking at
2042
+ # as few as k+1 of the coefficients of the degree n polynomial.
2043
+ # Using more samples reduces the error involved in degree
2044
+ # reduction, but is slower. More testing might reveal a better
2045
+ # way to select the number of samples here.
2046
+
2047
+ samps = min(n+1, next+5)
2048
+ bd = bernstein_down(next, n, samps)
2049
+
2050
+ # For each coefficient in the reduced polynomial, we see how
2051
+ # it varies as the (sampled) coefficients in the original
2052
+ # polynomial change by +/- 1. Then we take the reduced
2053
+ # coefficient which changes the most, and call that the expected
2054
+ # error. We can multiply this by the error in the original
2055
+ # polynomial, and be fairly certain (absolutely certain?) that
2056
+ # the error in the reduced polynomial will be no better
2057
+ # than this product.
2058
+ expected_err = max([sum([abs(x) for x in bd.row(k)]) for k in range(next+1)])
2059
+
2060
+ # bdd = bd.denominator()
2061
+ # bdi = MatrixSpace(ZZ, next+1, samps, sparse=False)(bd * bdd)
2062
+ (bdi, bdd) = bd._clear_denom()
2063
+
2064
+ dr_cache[n] = (next, bd, expected_err.floor(), (bdi, bdd))
2065
+ n = next
2066
+
2067
+
2068
+ def bernstein_down(d1, d2, s):
2069
+ """
2070
+ Given polynomial degrees d1 and d2 (where d1 < d2), and a number
2071
+ of samples s, computes a matrix bd.
2072
+
2073
+ If you have a Bernstein polynomial of formal degree d2, and select
2074
+ s of its coefficients (according to subsample_vec), and multiply
2075
+ the resulting vector by bd, then you get the coefficients
2076
+ of a Bernstein polynomial of formal degree d1, where this second
2077
+ polynomial is a good approximation to the first polynomial over the
2078
+ region of the Bernstein basis.
2079
+
2080
+ EXAMPLES::
2081
+
2082
+ sage: from sage.rings.polynomial.real_roots import *
2083
+ sage: bernstein_down(3, 8, 5)
2084
+ [ 612/245 -348/245 -37/49 338/245 -172/245]
2085
+ [-724/441 132/49 395/441 -290/147 452/441]
2086
+ [ 452/441 -290/147 395/441 132/49 -724/441]
2087
+ [-172/245 338/245 -37/49 -348/245 612/245]
2088
+ """
2089
+
2090
+ # The use of the pseudoinverse means that the coefficients of the
2091
+ # reduced polynomial are selected according to a least-squares fit.
2092
+ # We would prefer to minimize the maximum error, rather than the
2093
+ # sum of the squares of the errors; but I don't know how to do that.
2094
+
2095
+ # Also, this pseudoinverse is very slow to compute if d1 is large.
2096
+ # Since the coefficients of bernstein_up(...) can be represented
2097
+ # with a fairly simple formula (see the implementation of
2098
+ # bernstein_up()), it seems possible that there is some sort of
2099
+ # formula for the coefficients of the pseudoinverse that would be
2100
+ # faster than the computation here.
2101
+
2102
+ return pseudoinverse(bernstein_up(d1, d2, s))
2103
+
2104
+
2105
+ def pseudoinverse(m):
2106
+ mt = m.transpose()
2107
+ return ~(mt * m) * mt
2108
+
2109
+
2110
+ def bernstein_up(d1, d2, s=None):
2111
+ """
2112
+ Given polynomial degrees d1 and d2, where d1 < d2, compute a matrix bu.
2113
+
2114
+ If you have a Bernstein polynomial of formal degree d1, and
2115
+ multiply its coefficient vector by bu, then the result is the
2116
+ coefficient vector of the same polynomial represented as a
2117
+ Bernstein polynomial of formal degree d2.
2118
+
2119
+ If s is not None, then it represents a number of samples; then the
2120
+ product only gives s of the coefficients of the new Bernstein polynomial,
2121
+ selected according to subsample_vec.
2122
+
2123
+ EXAMPLES::
2124
+
2125
+ sage: from sage.rings.polynomial.real_roots import *
2126
+ sage: bernstein_down(3, 7, 4)
2127
+ [ 12/5 -4 3 -2/5]
2128
+ [-13/15 16/3 -4 8/15]
2129
+ [ 8/15 -4 16/3 -13/15]
2130
+ [ -2/5 3 -4 12/5]
2131
+ """
2132
+ if s is None:
2133
+ s = d1 + 1
2134
+ MS = MatrixSpace(QQ, s, d1+1, sparse=False)
2135
+ m = MS()
2136
+ scale = factorial(d2)/factorial(d2-d1)
2137
+ for b in range(d1 + 1):
2138
+ scale2 = scale / binomial(d1, b)
2139
+ if (d1 - b) & 1 == 1:
2140
+ scale2 = -scale2
2141
+ scale2 = ~scale2
2142
+ for a in range(s):
2143
+ ra = ZZ(subsample_vec(a, s, d2 + 1))
2144
+ m[a, b] = prod([ra-i for i in range(b)]) * prod([ra-i for i in range(d2-d1+b+1, d2+1)]) * scale2
2145
+
2146
+ return m
2147
+
2148
+
2149
+ cdef int subsample_vec(int a, int slen, int llen) noexcept:
2150
+ """
2151
+ Given a vector of length llen, and slen < llen, we want to
2152
+ select slen of the elements of the vector, evenly spaced.
2153
+
2154
+ Given an index 0 <= a < slen, this function computes the index
2155
+ in the original vector of length llen corresponding to a.
2156
+
2157
+ EXAMPLES::
2158
+
2159
+ sage: from sage.rings.polynomial.real_roots import *
2160
+ sage: [subsample_vec_doctest(a, 10, 100) for a in range(10)]
2161
+ [5, 15, 25, 35, 45, 54, 64, 74, 84, 94]
2162
+ sage: [subsample_vec_doctest(a, 3, 4) for a in range(3)]
2163
+ [1, 2, 3]
2164
+ """
2165
+ # round((a + 0.5) * (llen - 1) / slen)
2166
+ # round((2*a + 1) * (llen - 1) / (2 * slen)
2167
+ # floor(((2*a + 1) * (llen - 1) + slen) / (2 * slen))
2168
+ return ((2*a + 1) * (llen - 1) + slen) // (2 * slen)
2169
+
2170
+
2171
+ def subsample_vec_doctest(a, slen, llen):
2172
+ return subsample_vec(a, slen, llen)
2173
+
2174
+
2175
+ def maximum_root_first_lambda(p):
2176
+ r"""
2177
+ Given a polynomial with real coefficients, computes an upper bound
2178
+ on its largest real root.
2179
+
2180
+ This is using the first-\lambda algorithm from
2181
+ "Implementations of a New Theorem for Computing Bounds for Positive
2182
+ Roots of Polynomials", by Akritas, Strzebo\'nski, and Vigklas.
2183
+
2184
+ EXAMPLES::
2185
+
2186
+ sage: from sage.rings.polynomial.real_roots import *
2187
+ sage: x = polygen(ZZ)
2188
+ sage: maximum_root_first_lambda((x-1)*(x-2)*(x-3))
2189
+ 6.00000000000001
2190
+ sage: maximum_root_first_lambda((x+1)*(x+2)*(x+3))
2191
+ 0.000000000000000
2192
+ sage: maximum_root_first_lambda(x^2 - 1)
2193
+ 1.00000000000000
2194
+ """
2195
+ n = p.degree()
2196
+ if p[n] < 0:
2197
+ p = -p
2198
+ cl = [RIF(x) for x in p.list()]
2199
+ return cl_maximum_root_first_lambda(cl)
2200
+
2201
+
2202
+ def cl_maximum_root_first_lambda(cl):
2203
+ r"""
2204
+ Given a polynomial represented by a list of its coefficients
2205
+ (as RealIntervalFieldElements), compute an upper bound on its
2206
+ largest real root.
2207
+
2208
+ Uses the first-\lambda algorithm from "Implementations of a New Theorem
2209
+ for Computing Bounds for Positive Roots of Polynomials",
2210
+ by Akritas, Strzebo\'nski, and Vigklas.
2211
+
2212
+ EXAMPLES::
2213
+
2214
+ sage: from sage.rings.polynomial.real_roots import *
2215
+ sage: cl_maximum_root_first_lambda([RIF(-1), RIF(0), RIF(1)])
2216
+ 1.00000000000000
2217
+
2218
+ TESTS::
2219
+
2220
+ sage: bnd = cl_maximum_root_first_lambda(list(map(RIF, [0, 0, 0, 14, 1])))
2221
+ sage: bnd, bnd.parent()
2222
+ (0.000000000000000,
2223
+ Real Field with 53 bits of precision and rounding RNDU)
2224
+ """
2225
+ n = len(cl) - 1
2226
+ assert cl[n] > 0
2227
+ pending_pos_coeff = cl[n]
2228
+ pending_pos_exp = n
2229
+ lastPos = True
2230
+ posCounter = 1
2231
+ negCounter = 0
2232
+ pos = []
2233
+ neg = []
2234
+ for j in range(n-1, -2, -1):
2235
+ if j < 0:
2236
+ coeff = 1
2237
+ else:
2238
+ coeff = cl[j]
2239
+ if coeff < 0:
2240
+ neg += [(coeff, j)]
2241
+ lastPos = False
2242
+ negCounter = negCounter+1
2243
+ if coeff > 0:
2244
+ if negCounter > posCounter:
2245
+ chunks = negCounter - posCounter + 1
2246
+ pos += [(pending_pos_coeff / chunks, pending_pos_exp)] * chunks
2247
+ posCounter = negCounter
2248
+ else:
2249
+ pos += [(pending_pos_coeff, pending_pos_exp)]
2250
+ pending_pos_coeff = coeff
2251
+ pending_pos_exp = j
2252
+ posCounter = posCounter+1
2253
+
2254
+ if not neg:
2255
+ return RIF.upper_field().zero()
2256
+
2257
+ max_ub_log = RIF('-infinity')
2258
+ for j in range(len(neg)):
2259
+ cur_ub_log = (-neg[j][0] / pos[j][0]).log() / (pos[j][1] - neg[j][1])
2260
+ max_ub_log = max_ub_log.union(cur_ub_log)
2261
+
2262
+ return max_ub_log.upper().exp()
2263
+
2264
+
2265
+ def maximum_root_local_max(p):
2266
+ r"""
2267
+ Given a polynomial with real coefficients, computes an upper bound
2268
+ on its largest real root, using the local-max algorithm from
2269
+ "Implementations of a New Theorem for Computing Bounds for Positive
2270
+ Roots of Polynomials", by Akritas, Strzebo\'nski, and Vigklas.
2271
+
2272
+ EXAMPLES::
2273
+
2274
+ sage: from sage.rings.polynomial.real_roots import *
2275
+ sage: x = polygen(ZZ)
2276
+ sage: maximum_root_local_max((x-1)*(x-2)*(x-3))
2277
+ 12.0000000000001
2278
+ sage: maximum_root_local_max((x+1)*(x+2)*(x+3))
2279
+ 0.000000000000000
2280
+ sage: maximum_root_local_max(x^2 - 1)
2281
+ 1.41421356237310
2282
+ """
2283
+ n = p.degree()
2284
+ if p[n] < 0:
2285
+ p = -p
2286
+ cl = [RIF(x) for x in p.list()]
2287
+ return cl_maximum_root_local_max(cl)
2288
+
2289
+
2290
+ def cl_maximum_root_local_max(cl):
2291
+ r"""
2292
+ Given a polynomial represented by a list of its coefficients
2293
+ (as RealIntervalFieldElements), compute an upper bound on its
2294
+ largest real root.
2295
+
2296
+ Uses the local-max algorithm from "Implementations of a New Theorem
2297
+ for Computing Bounds for Positive Roots of Polynomials",
2298
+ by Akritas, Strzebo\'nski, and Vigklas.
2299
+
2300
+ EXAMPLES::
2301
+
2302
+ sage: from sage.rings.polynomial.real_roots import *
2303
+ sage: cl_maximum_root_local_max([RIF(-1), RIF(0), RIF(1)])
2304
+ 1.41421356237310
2305
+ """
2306
+ n = len(cl) - 1
2307
+ assert cl[n] > 0
2308
+ max_pos_coeff = cl[n]
2309
+ max_pos_exp = n
2310
+ max_pos_uses = 0
2311
+ max_ub_log = RIF('-infinity')
2312
+
2313
+ for j in range(n-1, -1, -1):
2314
+ if cl[j] < 0:
2315
+ max_pos_uses = max_pos_uses+1
2316
+ cur_ub_log = (-cl[j] / (max_pos_coeff >> max_pos_uses)).log() / (max_pos_exp - j)
2317
+ max_ub_log = max_ub_log.union(cur_ub_log)
2318
+ elif cl[j] > max_pos_coeff:
2319
+ max_pos_coeff = cl[j]
2320
+ max_pos_exp = j
2321
+ max_pos_uses = 0
2322
+
2323
+ return max_ub_log.upper().exp()
2324
+
2325
+
2326
+ def cl_maximum_root(cl):
2327
+ r"""
2328
+ Given a polynomial represented by a list of its coefficients
2329
+ (as RealIntervalFieldElements), compute an upper bound on its
2330
+ largest real root.
2331
+
2332
+ Uses two algorithms of Akritas, Strzebo\'nski, and Vigklas, and
2333
+ picks the better result.
2334
+
2335
+ EXAMPLES::
2336
+
2337
+ sage: from sage.rings.polynomial.real_roots import *
2338
+ sage: cl_maximum_root([RIF(-1), RIF(0), RIF(1)])
2339
+ 1.00000000000000
2340
+ """
2341
+ n = len(cl) - 1
2342
+ if cl[n] < 0:
2343
+ cl = [-x for x in cl]
2344
+ return min(cl_maximum_root_first_lambda(cl),
2345
+ cl_maximum_root_local_max(cl))
2346
+
2347
+
2348
+ def root_bounds(p):
2349
+ r"""
2350
+ Given a polynomial with real coefficients, computes a lower and
2351
+ upper bound on its real roots. Uses algorithms of
2352
+ Akritas, Strzebo\'nski, and Vigklas.
2353
+
2354
+ EXAMPLES::
2355
+
2356
+ sage: from sage.rings.polynomial.real_roots import *
2357
+ sage: x = polygen(ZZ)
2358
+ sage: root_bounds((x-1)*(x-2)*(x-3))
2359
+ (0.545454545454545, 6.00000000000001)
2360
+ sage: root_bounds(x^2)
2361
+ (0.000000000000000, 0.000000000000000)
2362
+ sage: root_bounds(x*(x+1))
2363
+ (-1.00000000000000, 0.000000000000000)
2364
+ sage: root_bounds((x+2)*(x-3))
2365
+ (-2.44948974278317, 3.46410161513776)
2366
+ sage: root_bounds(x^995 * (x^2 - 9999) - 1)
2367
+ (-99.9949998749937, 141.414284992713)
2368
+ sage: root_bounds(x^995 * (x^2 - 9999) + 1)
2369
+ (-141.414284992712, 99.9949998749938)
2370
+
2371
+ If we can see that the polynomial has no real roots, return None. ::
2372
+
2373
+ sage: root_bounds(x^2 + 1) is None
2374
+ True
2375
+ """
2376
+ n = p.degree()
2377
+ if p[n] < 0:
2378
+ p = -p
2379
+ cl = [RIF(x) for x in p.list()]
2380
+
2381
+ cdef int zero_roots = 0
2382
+ while cl[0] == 0:
2383
+ cl.pop(0)
2384
+ zero_roots = zero_roots + 1
2385
+ n = n-1
2386
+
2387
+ if n == 0:
2388
+ # not RIF.zero().endpoints() because of MPFI's convention that the
2389
+ # upper bound is -0.
2390
+ return RIF.lower_field().zero(), RIF.upper_field().zero()
2391
+
2392
+ ub = cl_maximum_root(cl)
2393
+
2394
+ neg_cl = copy(cl)
2395
+ for j in range(n-1, -1, -2):
2396
+ neg_cl[j] = -neg_cl[j]
2397
+
2398
+ lb = -cl_maximum_root(neg_cl)
2399
+
2400
+ if ub == 0 and lb == 0:
2401
+ if zero_roots == 0:
2402
+ return None
2403
+ else:
2404
+ return (lb, ub)
2405
+
2406
+ if ub == 0 and zero_roots == 0:
2407
+ swap_neg_cl = copy(neg_cl)
2408
+ swap_neg_cl.reverse()
2409
+ ub = (-(~RIF(cl_maximum_root(swap_neg_cl)))).upper()
2410
+
2411
+ if lb == 0 and zero_roots == 0:
2412
+ swap_cl = copy(cl)
2413
+ swap_cl.reverse()
2414
+ lb = (~RIF(cl_maximum_root(swap_cl))).lower()
2415
+
2416
+ return (lb, ub)
2417
+
2418
+
2419
+ def rational_root_bounds(p):
2420
+ """
2421
+ Given a polynomial p with real coefficients, computes rationals
2422
+ a and b, such that for every real root r of p, a < r < b.
2423
+ We try to find rationals which bound the roots somewhat tightly,
2424
+ yet are simple (have small numerators and denominators).
2425
+
2426
+ EXAMPLES::
2427
+
2428
+ sage: from sage.rings.polynomial.real_roots import *
2429
+ sage: x = polygen(ZZ)
2430
+ sage: rational_root_bounds((x-1)*(x-2)*(x-3))
2431
+ (0, 7)
2432
+ sage: rational_root_bounds(x^2)
2433
+ (-1/2, 1/2)
2434
+ sage: rational_root_bounds(x*(x+1))
2435
+ (-3/2, 1/2)
2436
+ sage: rational_root_bounds((x+2)*(x-3))
2437
+ (-3, 6)
2438
+ sage: rational_root_bounds(x^995 * (x^2 - 9999) - 1)
2439
+ (-100, 1000/7)
2440
+ sage: rational_root_bounds(x^995 * (x^2 - 9999) + 1)
2441
+ (-142, 213/2)
2442
+
2443
+ If we can see that the polynomial has no real roots, return None.
2444
+ sage: rational_root_bounds(x^2 + 7) is None
2445
+ True
2446
+ """
2447
+
2448
+ # There are two stages to the root isolation process. First,
2449
+ # we convert the polynomial to the Bernstein basis given by
2450
+ # the root bounds, exactly; then we isolate the roots from
2451
+ # that Bernstein basis, using interval arithmetic.
2452
+
2453
+ # We want the root bounds to be as small as possible, because that
2454
+ # speeds up the second phase; but we also want them to be as
2455
+ # simple as possible, because that speeds up the first phase.
2456
+
2457
+ # As a heuristic, given a polynomial of degree d with floating-point
2458
+ # root bounds lb and ub, we compute simple rational root bounds
2459
+ # rlb and rub such that lb - (ub - lb)/sqrt(d) <= rlb <= lb,
2460
+ # and ub <= rub <= ub + (ub - lb)/sqrt(d). Very little testing
2461
+ # was done to come up with this heuristic, and it can probably
2462
+ # be improved.
2463
+
2464
+ if p.degree() == 0:
2465
+ return (QQ(-1), QQ(1))
2466
+
2467
+ sqrtd = sqrt(RR(p.degree()))
2468
+ bounds = root_bounds(p)
2469
+ if bounds is None:
2470
+ return None
2471
+ (lb, ub) = bounds
2472
+
2473
+ if lb == ub:
2474
+ # The code below would give overly precise bounds in this case,
2475
+ # giving very non-simple isolating intervals in the result.
2476
+ # We don't need tight root bounds to quickly find the roots
2477
+ # of a linear polynomial, so go for simple root bounds.
2478
+
2479
+ b = QQ(lb)
2480
+
2481
+ return (b - QQ_1_2, b + QQ_1_2)
2482
+
2483
+ # XXX A gross hack. Sometimes, root_bounds() gives a lower or
2484
+ # upper bound which is a root. We want bounds which are
2485
+ # not roots, so we just spread out the bounds a tiny bit.
2486
+ # (It might be more efficient to check the bounds from root_bounds()
2487
+ # and, if they are roots, use that information to factor out a linear
2488
+ # polynomial. However, as far as I can tell, root_bounds() only
2489
+ # gives roots as bounds on toy examples; so this is not too inefficient.)
2490
+ lb = RR(lb).nextbelow()
2491
+ ub = RR(ub).nextabove()
2492
+
2493
+ # Given the current implementation of to_bernstein, we want rlb
2494
+ # and (rub/rlb - 1) to be simple rationals -- we don't really care
2495
+ # about the simplicity of rub by itself. (Or else we want rlb to
2496
+ # be zero, and rub to be a simple rational.)
2497
+
2498
+ ilb = RIF(lb - (ub - lb)/sqrtd, lb)
2499
+ rlb = ilb.simplest_rational()
2500
+
2501
+ if rlb == 0:
2502
+ iub = RIF(ub, ub + (ub - lb)/sqrtd)
2503
+ rub = iub.simplest_rational()
2504
+ return (rlb, rub)
2505
+
2506
+ # We want to compute an interval for the upper bound,
2507
+ # iub = [ub .. ub + (ub - lb)/sqrtd],
2508
+ # and then compute (iub/ilb - 1).simplest_rational().
2509
+ # However, we want to compute this
2510
+ # interval with inward instead of outward rounding. Instead,
2511
+ # we compute the lower and upper bounds of the interval separately.
2512
+
2513
+ iub_l = RIF(ub)
2514
+ iub_h = RIF(ub + (ub - lb)/sqrtd)
2515
+
2516
+ iub_l2 = iub_l/rlb - 1
2517
+ iub_h2 = iub_h/rlb - 1
2518
+
2519
+ if iub_l2 < iub_h2:
2520
+ rub = (RIF(iub_l2.upper(), iub_h2.lower()).simplest_rational() + 1)*rlb
2521
+ else:
2522
+ rub = (RIF(iub_h2.upper(), iub_l2.lower()).simplest_rational() + 1)*rlb
2523
+
2524
+ return (rlb, rub)
2525
+
2526
+
2527
+ class PrecisionError(ValueError):
2528
+ pass
2529
+
2530
+
2531
+ class bernstein_polynomial_factory:
2532
+ """
2533
+ An abstract base class for bernstein_polynomial factories. That
2534
+ is, elements of subclasses represent Bernstein polynomials
2535
+ (exactly), and are responsible for creating
2536
+ interval_bernstein_polynomial_integer approximations at arbitrary
2537
+ precision.
2538
+
2539
+ Supports four methods, coeffs_bitsize(), bernstein_polynomial(),
2540
+ lsign(), and usign(). The coeffs_bitsize() method gives an
2541
+ integer approximation to the log2 of the max of the absolute
2542
+ values of the Bernstein coefficients. The
2543
+ bernstein_polynomial(scale_log2) method gives an approximation
2544
+ where the maximum coefficient has approximately coeffs_bitsize() -
2545
+ scale_log2 bits. The lsign() and usign() methods give the (exact)
2546
+ sign of the first and last coefficient, respectively.
2547
+ """
2548
+
2549
+ def _sign(self, v):
2550
+ if v > 0:
2551
+ return 1
2552
+ if v < 0:
2553
+ return -1
2554
+ return 0
2555
+
2556
+ def lsign(self):
2557
+ """
2558
+ Return the sign of the first coefficient of this
2559
+ Bernstein polynomial.
2560
+ """
2561
+ return self._sign(self.coeffs[0])
2562
+
2563
+ def usign(self):
2564
+ """
2565
+ Return the sign of the last coefficient of this
2566
+ Bernstein polynomial.
2567
+ """
2568
+ return self._sign(self.coeffs[-1])
2569
+
2570
+
2571
+ class bernstein_polynomial_factory_intlist(bernstein_polynomial_factory):
2572
+ """
2573
+ This class holds an exact Bernstein polynomial (represented
2574
+ as a list of integer coefficients), and returns arbitrarily-precise
2575
+ interval approximations of this polynomial on demand.
2576
+ """
2577
+
2578
+ def __init__(self, coeffs):
2579
+ """
2580
+ Initialize a ``bernstein_polynomial_factory_intlist``,
2581
+ given a list of integer coefficients.
2582
+
2583
+ EXAMPLES::
2584
+
2585
+ sage: from sage.rings.polynomial.real_roots import *
2586
+ sage: bernstein_polynomial_factory_intlist([1, 2, 3])
2587
+ degree 2 Bernstein factory with 2-bit integer coefficients
2588
+ """
2589
+ self.coeffs = coeffs
2590
+
2591
+ def __repr__(self):
2592
+ """
2593
+ Return a short summary of this Bernstein polynomial factory.
2594
+
2595
+ EXAMPLES::
2596
+
2597
+ sage: from sage.rings.polynomial.real_roots import *
2598
+ sage: bernstein_polynomial_factory_intlist([1, 2, 3, 4000])
2599
+ degree 3 Bernstein factory with 12-bit integer coefficients
2600
+ """
2601
+
2602
+ return "degree %d Bernstein factory with %d-bit integer coefficients" % (len(self.coeffs) - 1, self.coeffs_bitsize())
2603
+
2604
+ def coeffs_bitsize(self):
2605
+ """
2606
+ Compute the approximate log2 of the maximum of the absolute
2607
+ values of the coefficients.
2608
+
2609
+ EXAMPLES::
2610
+
2611
+ sage: from sage.rings.polynomial.real_roots import *
2612
+ sage: bernstein_polynomial_factory_intlist([1, 2, 3, -60000]).coeffs_bitsize()
2613
+ 16
2614
+ """
2615
+ b = self.coeffs
2616
+ return max([bitsize(c) for c in b])
2617
+ # return intlist_size(self.coeffs)
2618
+
2619
+ def bernstein_polynomial(self, scale_log2):
2620
+ """
2621
+ Compute an interval_bernstein_polynomial_integer that approximates
2622
+ this polynomial, using the given scale_log2. (Smaller scale_log2
2623
+ values give more accurate approximations.)
2624
+
2625
+ EXAMPLES::
2626
+
2627
+ sage: from sage.rings.polynomial.real_roots import *
2628
+ sage: bpf = bernstein_polynomial_factory_intlist([10, -20, 30, -40])
2629
+ sage: print(bpf.bernstein_polynomial(0))
2630
+ degree 3 IBP with 6-bit coefficients
2631
+ sage: bpf.bernstein_polynomial(20)
2632
+ <IBP: ((0, -1, 0, -1) + [0 .. 1)) * 2^20; lsign 1>
2633
+ sage: bpf.bernstein_polynomial(0)
2634
+ <IBP: (10, -20, 30, -40) + [0 .. 1)>
2635
+ sage: bpf.bernstein_polynomial(-20)
2636
+ <IBP: ((10485760, -20971520, 31457280, -41943040) + [0 .. 1)) * 2^-20>
2637
+ """
2638
+ b = self.coeffs
2639
+ if scale_log2 < 0:
2640
+ shift = ZZ(-scale_log2)
2641
+ intv_b = [c << shift for c in b]
2642
+ else:
2643
+ shift = ZZ(scale_log2)
2644
+ intv_b = [c >> shift for c in b]
2645
+
2646
+ return interval_bernstein_polynomial_integer((ZZ ** len(b))(intv_b), zero_QQ, one_QQ, self.lsign(), self.usign(), 1, scale_log2, 0, zero_RIF)
2647
+ # return bp_of_intlist(self.coeffs, scale_log2)
2648
+
2649
+
2650
+ class bernstein_polynomial_factory_ratlist(bernstein_polynomial_factory):
2651
+ """
2652
+ This class holds an exact Bernstein polynomial (represented
2653
+ as a list of rational coefficients), and returns arbitrarily-precise
2654
+ interval approximations of this polynomial on demand.
2655
+ """
2656
+
2657
+ def __init__(self, coeffs):
2658
+ """
2659
+ Initialize a ``bernstein_polynomial_factory_intlist``,
2660
+ given a list of rational coefficients.
2661
+
2662
+ EXAMPLES::
2663
+
2664
+ sage: from sage.rings.polynomial.real_roots import *
2665
+ sage: bernstein_polynomial_factory_ratlist([1, 1/2, 1/3])
2666
+ degree 2 Bernstein factory with 0-bit rational coefficients
2667
+ """
2668
+ self.coeffs = coeffs
2669
+
2670
+ def __repr__(self):
2671
+ """
2672
+ Return a short summary of this Bernstein polynomial factory.
2673
+
2674
+ EXAMPLES::
2675
+
2676
+ sage: from sage.rings.polynomial.real_roots import *
2677
+ sage: bernstein_polynomial_factory_ratlist([1, 2, 3, 4000/17])
2678
+ degree 3 Bernstein factory with 7-bit rational coefficients
2679
+ """
2680
+
2681
+ return "degree %d Bernstein factory with %d-bit rational coefficients" % (len(self.coeffs) - 1, self.coeffs_bitsize())
2682
+
2683
+ def coeffs_bitsize(self):
2684
+ """
2685
+ Compute the approximate log2 of the maximum of the absolute
2686
+ values of the coefficients.
2687
+
2688
+ EXAMPLES::
2689
+
2690
+ sage: from sage.rings.polynomial.real_roots import *
2691
+ sage: bernstein_polynomial_factory_ratlist([1, 2, 3, -60000]).coeffs_bitsize()
2692
+ 15
2693
+ sage: bernstein_polynomial_factory_ratlist([65535/65536]).coeffs_bitsize()
2694
+ -1
2695
+ sage: bernstein_polynomial_factory_ratlist([65536/65535]).coeffs_bitsize()
2696
+ 1
2697
+ """
2698
+
2699
+ # This returns an estimate of the log base 2 of the rational in the
2700
+ # list with largest absolute value. The estimate is an integer,
2701
+ # and within +/- 1 of the correct answer.
2702
+ r = max([bitsize(c.numerator()) - bitsize(c.denominator()) for c in self.coeffs])
2703
+ return r
2704
+
2705
+ def bernstein_polynomial(self, scale_log2):
2706
+ """
2707
+ Compute an interval_bernstein_polynomial_integer that approximates
2708
+ this polynomial, using the given scale_log2. (Smaller scale_log2
2709
+ values give more accurate approximations.)
2710
+
2711
+ EXAMPLES::
2712
+
2713
+ sage: from sage.rings.polynomial.real_roots import *
2714
+ sage: bpf = bernstein_polynomial_factory_ratlist([1/3, -22/7, 193/71, -140/99])
2715
+ sage: print(bpf.bernstein_polynomial(0))
2716
+ degree 3 IBP with 3-bit coefficients
2717
+ sage: bpf.bernstein_polynomial(20)
2718
+ <IBP: ((0, -1, 0, -1) + [0 .. 1)) * 2^20; lsign 1>
2719
+ sage: bpf.bernstein_polynomial(0)
2720
+ <IBP: (0, -4, 2, -2) + [0 .. 1); lsign 1>
2721
+ sage: bpf.bernstein_polynomial(-20)
2722
+ <IBP: ((349525, -3295525, 2850354, -1482835) + [0 .. 1)) * 2^-20>
2723
+ """
2724
+ b = self.coeffs
2725
+
2726
+ if scale_log2 < 0:
2727
+ intv_b = [(numerator(c) << (-scale_log2)) // denominator(c) for c in b]
2728
+ else:
2729
+ intv_b = [(numerator(c) >> scale_log2) // denominator(c) for c in b]
2730
+
2731
+ return interval_bernstein_polynomial_integer((ZZ ** len(b))(intv_b), zero_QQ, one_QQ, self.lsign(), self.usign(), 1, scale_log2, 0, zero_RIF)
2732
+ # return bp_of_ratlist(self.coeffs, scale_log2)
2733
+
2734
+
2735
+ class bernstein_polynomial_factory_ar(bernstein_polynomial_factory):
2736
+ """
2737
+ This class holds an exact Bernstein polynomial (represented as a
2738
+ list of algebraic real coefficients), and returns
2739
+ arbitrarily-precise interval approximations of this polynomial on
2740
+ demand.
2741
+ """
2742
+
2743
+ def __init__(self, poly, neg):
2744
+ """
2745
+ Initialize a ``bernstein_polynomial_factory_ar``,
2746
+ given a polynomial with algebraic real coefficients.
2747
+ If neg is True, then gives the Bernstein polynomial for
2748
+ the negative half-line; if neg is False, the positive.
2749
+
2750
+ EXAMPLES::
2751
+
2752
+ sage: from sage.rings.polynomial.real_roots import *
2753
+ sage: x = polygen(AA)
2754
+ sage: p = (x - 1) * (x - sqrt(AA(2))) * (x - 2)
2755
+ sage: bernstein_polynomial_factory_ar(p, False)
2756
+ degree 3 Bernstein factory with algebraic real coefficients
2757
+ """
2758
+ coeffs = to_bernstein_warp(poly)
2759
+ if neg:
2760
+ for i in range(1, len(coeffs), 2):
2761
+ coeffs[i] = -coeffs[i]
2762
+ sizes = []
2763
+ for c in coeffs:
2764
+ size = RIF(c).magnitude()
2765
+ if size > 0:
2766
+ sizes.append(size.log2().floor())
2767
+ else:
2768
+ sizes.append(-1000000)
2769
+
2770
+ self.coeffs = coeffs
2771
+ self.sizes = sizes
2772
+
2773
+ def __repr__(self):
2774
+ """
2775
+ Return a short summary of this Bernstein polynomial factory.
2776
+
2777
+ EXAMPLES::
2778
+
2779
+ sage: from sage.rings.polynomial.real_roots import *
2780
+ sage: x = polygen(AA)
2781
+ sage: p = (x - 1) * (x - sqrt(AA(2))) * (x - 2)
2782
+ sage: bernstein_polynomial_factory_ar(p, False)
2783
+ degree 3 Bernstein factory with algebraic real coefficients
2784
+ """
2785
+
2786
+ return "degree %d Bernstein factory with algebraic real coefficients" % (len(self.coeffs) - 1)
2787
+
2788
+ def coeffs_bitsize(self):
2789
+ """
2790
+ Compute the approximate log2 of the maximum of the absolute
2791
+ values of the coefficients.
2792
+
2793
+ EXAMPLES::
2794
+
2795
+ sage: from sage.rings.polynomial.real_roots import *
2796
+ sage: x = polygen(AA)
2797
+ sage: p = (x - 1) * (x - sqrt(AA(2))) * (x - 2)
2798
+ sage: bernstein_polynomial_factory_ar(p, False).coeffs_bitsize()
2799
+ 1
2800
+ """
2801
+ return max(self.sizes)
2802
+
2803
+ def bernstein_polynomial(self, scale_log2):
2804
+ """
2805
+ Compute an interval_bernstein_polynomial_integer that approximates
2806
+ this polynomial, using the given scale_log2. (Smaller scale_log2
2807
+ values give more accurate approximations.)
2808
+
2809
+ EXAMPLES::
2810
+
2811
+ sage: from sage.rings.polynomial.real_roots import *
2812
+ sage: x = polygen(AA)
2813
+ sage: p = (x - 1) * (x - sqrt(AA(2))) * (x - 2)
2814
+ sage: bpf = bernstein_polynomial_factory_ar(p, False)
2815
+ sage: print(bpf.bernstein_polynomial(0))
2816
+ degree 3 IBP with 2-bit coefficients
2817
+ sage: bpf.bernstein_polynomial(-20)
2818
+ <IBP: ((-2965821, 2181961, -1542880, 1048576) + [0 .. 1)) * 2^-20>
2819
+ sage: bpf = bernstein_polynomial_factory_ar(p, True)
2820
+ sage: bpf.bernstein_polynomial(-20)
2821
+ <IBP: ((-2965821, -2181962, -1542880, -1048576) + [0 .. 1)) * 2^-20>
2822
+ sage: p = x^2 - 1
2823
+ sage: bpf = bernstein_polynomial_factory_ar(p, False)
2824
+ sage: bpf.bernstein_polynomial(-10)
2825
+ <IBP: ((-1024, 0, 1024) + [0 .. 1)) * 2^-10>
2826
+ """
2827
+ res = (ZZ ** len(self.coeffs))(0)
2828
+ max_err = 0
2829
+
2830
+ for i in range(len(self.coeffs)):
2831
+ intv_c = RealIntervalField(max(self.sizes[i] - scale_log2 + 6, 6))(self.coeffs[i])
2832
+ if scale_log2 < 0:
2833
+ intv_c = intv_c << (-scale_log2)
2834
+ else:
2835
+ intv_c = intv_c >> scale_log2
2836
+
2837
+ # Compute lower and upper such that lower <= intv_c < upper
2838
+ lower = intv_c.lower().floor()
2839
+ upper = intv_c.upper().floor() + 1
2840
+
2841
+ res[i] = lower
2842
+ max_err = max(max_err, upper - lower)
2843
+
2844
+ return interval_bernstein_polynomial_integer(res, zero_QQ, one_QQ, self.lsign(), self.usign(), max_err, scale_log2, 0, zero_RIF)
2845
+
2846
+
2847
+ def split_for_targets(context ctx, interval_bernstein_polynomial bp, target_list, precise=False):
2848
+ """
2849
+ Given an interval Bernstein polynomial over a particular region
2850
+ (assumed to be a (not necessarily proper) subregion of [0 .. 1]),
2851
+ and a list of targets, uses de Casteljau's method to compute
2852
+ representations of the Bernstein polynomial over each target.
2853
+ Uses degree reduction as often as possible while maintaining the
2854
+ requested precision.
2855
+
2856
+ Each target is of the form (lgap, ugap, b). Suppose lgap.region()
2857
+ is (l1, l2), and ugap.region() is (u1, u2). Then we will compute
2858
+ an interval Bernstein polynomial over a region [l .. u], where
2859
+ l1 <= l <= l2 and u1 <= u <= u2. (split_for_targets() is free to
2860
+ select arbitrary region endpoints within these bounds; it picks
2861
+ endpoints which make the computation easier.) The third component
2862
+ of the target, b, is the maximum allowed scale_log2 of the result;
2863
+ this is used to decide when degree reduction is allowed.
2864
+
2865
+ The pair (l1, l2) can be replaced by None, meaning [-infinity .. 0];
2866
+ or, (u1, u2) can be replaced by None, meaning [1 .. infinity].
2867
+
2868
+ There is another constraint on the region endpoints selected by
2869
+ split_for_targets() for a target ((l1, l2), (u1, u2), b).
2870
+ We set a size goal g, such that (u - l) <= g * (u1 - l2).
2871
+ Normally g is 256/255, but if precise is True, then g is 65536/65535.
2872
+
2873
+ EXAMPLES::
2874
+
2875
+ sage: from sage.rings.polynomial.real_roots import *
2876
+ sage: bp = mk_ibpi([1000000, -2000000, 3000000, -4000000, -5000000, -6000000])
2877
+ sage: ctx = mk_context()
2878
+ sage: bps = split_for_targets(ctx, bp, [(rr_gap(1/1234567893, 1/1234567892, 1), rr_gap(1/1234567891, 1/1234567890, 1), 12), (rr_gap(1/3, 1/2, -1), rr_gap(2/3, 3/4, -1), 6)])
2879
+ sage: bps[0]
2880
+ <IBP: (999992, 999992, 999992) + [0 .. 15) over [8613397477114467984778830327/10633823966279326983230456482242756608 .. 591908168025934394813836527495938294787/730750818665451459101842416358141509827966271488]; level 2; slope_err 0.?e12>
2881
+ sage: bps[1]
2882
+ <IBP: (-1562500, -1875001, -2222223, -2592593, -2969137, -3337450) + [0 .. 4) over [1/2 .. 2863311531/4294967296]>
2883
+ """
2884
+ ntargs = len(target_list)
2885
+ if ntargs == 0:
2886
+ return []
2887
+
2888
+ bounds = bp.region()
2889
+
2890
+ out_of_bounds = False
2891
+
2892
+ cdef rr_gap l
2893
+ cdef rr_gap r
2894
+
2895
+ split_targets = []
2896
+ for l, r, _ in target_list:
2897
+ if l is None:
2898
+ split_targets += [(QQ(0), None, 0)]
2899
+ else:
2900
+ lbounds = relative_bounds(bounds, l.region())
2901
+ split_targets += [(lbounds[1], lbounds[0], l.sign)]
2902
+ if lbounds[0] > 0:
2903
+ out_of_bounds = True
2904
+ if r is None:
2905
+ split_targets += [(QQ.one(), None, 0)]
2906
+ else:
2907
+ rbounds = relative_bounds(bounds, r.region())
2908
+ split_targets += [(rbounds[0], rbounds[1], r.sign)]
2909
+ if rbounds[1] < 1:
2910
+ out_of_bounds = True
2911
+
2912
+ if precise:
2913
+ goal = Integer(65535)/65536
2914
+ else:
2915
+ goal = Integer(255)/256
2916
+
2917
+ if ntargs == 1 and not(out_of_bounds) and split_targets[1][0] - split_targets[0][0] >= goal:
2918
+ return [bp]
2919
+
2920
+ half = Integer(1)/2
2921
+ best_target = split_targets[0][0]
2922
+ best_index = 0
2923
+ for i in range(1, len(split_targets)):
2924
+ if abs(split_targets[i][0] - half) < abs(best_target - half):
2925
+ best_target = split_targets[i][0]
2926
+ best_index = i
2927
+
2928
+ split = wordsize_rational(split_targets[best_index][0], split_targets[best_index][1], ctx.wordsize)
2929
+
2930
+ (p1_, p2_, ok) = bp.de_casteljau(ctx, split, msign=split_targets[best_index][2])
2931
+ assert ok
2932
+
2933
+ cdef interval_bernstein_polynomial p1 = p1_
2934
+ cdef interval_bernstein_polynomial p2 = p2_
2935
+
2936
+ if bp.lft is not None:
2937
+ (a, b, c, d) = bp.lft
2938
+ left = b/d
2939
+ if c+d != 0:
2940
+ right = (a+b)/(c+d)
2941
+ width = right-left
2942
+ err = (a/2 + b)/(c/2 + d) - (left+right)/2
2943
+ else:
2944
+ width = RR(infinity)
2945
+ err = RR(infinity)
2946
+ slope = (a*d - b*c)/(d*d)
2947
+ ctx.dc_log_append(('lft', a, b, c, d, RR(left), RR(width), RR(slope/width), RR(err/width/width)))
2948
+ ctx.dc_log_append(('split_for_targets', best_index, split, bp.scale_log2, bp.bitsize, p1.bitsize, p2.bitsize))
2949
+
2950
+ target_list_splitpoint = (best_index + 1) // 2
2951
+ tl1 = target_list[:target_list_splitpoint]
2952
+ tl2 = target_list[target_list_splitpoint:]
2953
+
2954
+ if len(tl1) > 0:
2955
+ if True: # p1.region_width() / bp.region_width() < tiny:
2956
+ max_lsb = max([t[2] for t in tl1])
2957
+ p1 = p1.down_degree_iter(ctx, max_lsb)
2958
+ r1 = split_for_targets(ctx, p1, tl1)
2959
+ else:
2960
+ r1 = []
2961
+ if len(tl2) > 0:
2962
+ if True: # p2.region_width() / bp.region_width() < tiny:
2963
+ max_lsb = max([t[2] for t in tl2])
2964
+ p2 = p2.down_degree_iter(ctx, max_lsb)
2965
+ r2 = split_for_targets(ctx, p2, tl2)
2966
+ else:
2967
+ r2 = []
2968
+
2969
+ return r1 + r2
2970
+
2971
+
2972
+ cdef class ocean:
2973
+ """
2974
+ Given the tools we've defined so far, there are many possible root
2975
+ isolation algorithms that differ on where to select split points,
2976
+ what precision to work at when, and when to attempt degree
2977
+ reduction.
2978
+
2979
+ Here we implement one particular algorithm, which I call the
2980
+ ocean-island algorithm. We start with an interval Bernstein
2981
+ polynomial defined over the region [0 .. 1]. This region is
2982
+ the "ocean". Using de Casteljau's algorithm and Descartes'
2983
+ rule of signs, we divide this region into subregions which may
2984
+ contain roots, and subregions which are guaranteed not to contain
2985
+ roots. Subregions which may contain roots are "islands"; subregions
2986
+ known not to contain roots are "gaps".
2987
+
2988
+ All the real root isolation work happens in class island. See the
2989
+ documentation of that class for more information.
2990
+
2991
+ An island can be told to refine itself until it contains only a
2992
+ single root. This may not succeed, if the island's interval
2993
+ Bernstein polynomial does not have enough precision. The ocean
2994
+ basically loops, refining each of its islands, then increasing the
2995
+ precision of islands which did not succeed in isolating a single
2996
+ root; until all islands are done.
2997
+
2998
+ Increasing the precision of unsuccessful islands is done in a
2999
+ single pass using split_for_target(); this means it is possible
3000
+ to share work among multiple islands.
3001
+ """
3002
+
3003
+ def __init__(self, ctx, bpf, mapping):
3004
+ """
3005
+ Initialize an ocean from a context and a Bernstein polynomial
3006
+ factory.
3007
+
3008
+ EXAMPLES::
3009
+
3010
+ sage: from sage.rings.polynomial.real_roots import *
3011
+ sage: ocean(mk_context(), bernstein_polynomial_factory_ratlist([1/3, -22/7, 193/71, -140/99]), lmap)
3012
+ ocean with precision 120 and 1 island(s)
3013
+ """
3014
+
3015
+ # Islands and gaps are maintained in a doubly-linked (circular)
3016
+ # list. Islands point to the gaps on either side, and gaps
3017
+ # point to the islands on either side.
3018
+
3019
+ # The list starts with self.lgap, which is the gap that starts
3020
+ # at 0; it ends at self.endpoint, which is a fictional island
3021
+ # after the gap that ends at 1.
3022
+
3023
+ # The initial gaps are unique in being 0-width; all gaps that
3024
+ # are created during execution of the algorithm have positive
3025
+ # width.
3026
+
3027
+ # Note that the constructor for islands side-effects its argument
3028
+ # gaps, so that they point to the island as their neighbor.
3029
+
3030
+ self.ctx = ctx
3031
+ self.bpf = bpf
3032
+ self.mapping = mapping
3033
+ self.lgap = rr_gap(zero_QQ, zero_QQ, bpf.lsign())
3034
+ rgap = rr_gap(one_QQ, one_QQ, bpf.usign())
3035
+ self.endpoint = island(None, rgap, self.lgap)
3036
+ self.msb = bpf.coeffs_bitsize()
3037
+ self.prec = 120
3038
+
3039
+ cdef island isle = island(self.approx_bp(self.msb - self.prec), self.lgap, rgap)
3040
+ if isle.bp.max_variations == 0:
3041
+ self.lgap.risland = self.endpoint
3042
+ self.endpoint.lgap = self.lgap
3043
+
3044
+ def __repr__(self):
3045
+ """
3046
+ Return a short summary of this root isolator.
3047
+
3048
+ EXAMPLES::
3049
+
3050
+ sage: from sage.rings.polynomial.real_roots import *
3051
+ sage: ocean(mk_context(), bernstein_polynomial_factory_ratlist([1/3, -22/7, 193/71, -140/99]), lmap)
3052
+ ocean with precision 120 and 1 island(s)
3053
+ """
3054
+
3055
+ cdef int isle_count = 0
3056
+ cdef island isle = self.lgap.risland
3057
+ while isle is not self.endpoint:
3058
+ isle_count = isle_count + 1
3059
+ isle = isle.rgap.risland
3060
+
3061
+ return "ocean with precision %d and %d island(s)" % (self.prec, isle_count)
3062
+
3063
+ def _islands(self):
3064
+ """
3065
+ Return a list of the islands in this ocean (for debugging purposes).
3066
+
3067
+ EXAMPLES::
3068
+
3069
+ sage: from sage.rings.polynomial.real_roots import *
3070
+ sage: oc = ocean(mk_context(), bernstein_polynomial_factory_ratlist([1/3, -22/7, 193/71, -140/99]), lmap)
3071
+ sage: oc._islands()
3072
+ [island of width 1.00000000000000]
3073
+ """
3074
+
3075
+ islands = []
3076
+ cdef island isle = self.lgap.risland
3077
+ while isle is not self.endpoint:
3078
+ islands.append(isle)
3079
+ isle = isle.rgap.risland
3080
+
3081
+ return islands
3082
+
3083
+ def approx_bp(self, scale_log2):
3084
+ """
3085
+ Return an approximation to our Bernstein polynomial with the
3086
+ given scale_log2.
3087
+
3088
+ EXAMPLES::
3089
+
3090
+ sage: from sage.rings.polynomial.real_roots import *
3091
+ sage: oc = ocean(mk_context(), bernstein_polynomial_factory_ratlist([1/3, -22/7, 193/71, -140/99]), lmap)
3092
+ sage: oc.approx_bp(0)
3093
+ <IBP: (0, -4, 2, -2) + [0 .. 1); lsign 1>
3094
+ sage: oc.approx_bp(-20)
3095
+ <IBP: ((349525, -3295525, 2850354, -1482835) + [0 .. 1)) * 2^-20>
3096
+ """
3097
+ return self.bpf.bernstein_polynomial(scale_log2)
3098
+
3099
+ def find_roots(self):
3100
+ """
3101
+ Isolate all roots in this ocean.
3102
+
3103
+ EXAMPLES::
3104
+
3105
+ sage: from sage.rings.polynomial.real_roots import *
3106
+ sage: oc = ocean(mk_context(), bernstein_polynomial_factory_ratlist([1/3, -22/7, 193/71, -140/99]), lmap)
3107
+ sage: oc
3108
+ ocean with precision 120 and 1 island(s)
3109
+ sage: oc.find_roots()
3110
+ sage: oc
3111
+ ocean with precision 120 and 3 island(s)
3112
+ sage: oc = ocean(mk_context(), bernstein_polynomial_factory_ratlist([1, 0, -1111/2, 0, 11108889/14, 0, 0, 0, 0, -1]), lmap)
3113
+ sage: oc.find_roots()
3114
+ sage: oc
3115
+ ocean with precision 240 and 3 island(s)
3116
+ """
3117
+ while not self.all_done():
3118
+ self.refine_all()
3119
+ self.increase_precision()
3120
+
3121
+ def roots(self):
3122
+ """
3123
+ Return the locations of all islands in this ocean. (If run
3124
+ after find_roots(), this is the location of all roots in the ocean.)
3125
+
3126
+ EXAMPLES::
3127
+
3128
+ sage: from sage.rings.polynomial.real_roots import *
3129
+ sage: oc = ocean(mk_context(), bernstein_polynomial_factory_ratlist([1/3, -22/7, 193/71, -140/99]), lmap)
3130
+ sage: oc.find_roots()
3131
+ sage: oc.roots()
3132
+ [(1/32, 1/16), (1/2, 5/8), (3/4, 7/8)]
3133
+ sage: oc = ocean(mk_context(), bernstein_polynomial_factory_ratlist([1, 0, -1111/2, 0, 11108889/14, 0, 0, 0, 0, -1]), lmap)
3134
+ sage: oc.find_roots()
3135
+ sage: oc.roots()
3136
+ [(95761241267509487747625/9671406556917033397649408, 191522482605387719863145/19342813113834066795298816), (1496269395904347376805/151115727451828646838272, 374067366568272936175/37778931862957161709568), (31/32, 63/64)]
3137
+ """
3138
+ rts = []
3139
+ cdef island isle = self.lgap.risland
3140
+ while isle is not self.endpoint:
3141
+ rts.append((isle.lgap.upper, isle.rgap.lower))
3142
+ isle = isle.rgap.risland
3143
+ return rts
3144
+
3145
+ def refine_all(self):
3146
+ """
3147
+ Refine all islands which are not done (which are not known to
3148
+ contain exactly one root).
3149
+
3150
+ EXAMPLES::
3151
+
3152
+ sage: from sage.rings.polynomial.real_roots import *
3153
+ sage: oc = ocean(mk_context(), bernstein_polynomial_factory_ratlist([1/3, -22/7, 193/71, -140/99]), lmap)
3154
+ sage: oc
3155
+ ocean with precision 120 and 1 island(s)
3156
+ sage: oc.refine_all()
3157
+ sage: oc
3158
+ ocean with precision 120 and 3 island(s)
3159
+ """
3160
+ cdef island isle = self.lgap.risland
3161
+ while isle is not self.endpoint:
3162
+ if not isle.done(self.ctx):
3163
+ isle.refine(self.ctx)
3164
+ isle = isle.rgap.risland
3165
+
3166
+ def all_done(self):
3167
+ """
3168
+ Return ``True`` iff all islands are known to contain exactly one root.
3169
+
3170
+ EXAMPLES::
3171
+
3172
+ sage: from sage.rings.polynomial.real_roots import *
3173
+ sage: oc = ocean(mk_context(), bernstein_polynomial_factory_ratlist([1/3, -22/7, 193/71, -140/99]), lmap)
3174
+ sage: oc.all_done()
3175
+ False
3176
+ sage: oc.find_roots()
3177
+ sage: oc.all_done()
3178
+ True
3179
+ """
3180
+ cdef island isle = self.lgap.risland
3181
+ while isle is not self.endpoint:
3182
+ if not isle.done(self.ctx):
3183
+ return False
3184
+ if not isle.has_root():
3185
+ isle.lgap.risland = isle.rgap.risland
3186
+ isle.rgap.risland.lgap = isle.lgap
3187
+ isle.lgap.upper = isle.rgap.upper
3188
+ isle = isle.rgap.risland
3189
+ return True
3190
+
3191
+ def reset_root_width(self, int isle_num, target_width):
3192
+ """
3193
+ Require that the isle_num island have a width at most target_width.
3194
+
3195
+ If this is followed by a call to find_roots(), then the
3196
+ corresponding root will be refined to the specified width.
3197
+
3198
+ EXAMPLES::
3199
+
3200
+ sage: from sage.rings.polynomial.real_roots import *
3201
+ sage: oc = ocean(mk_context(), bernstein_polynomial_factory_ratlist([-1, -1, 1]), lmap)
3202
+ sage: oc.find_roots()
3203
+ sage: oc.roots()
3204
+ [(1/2, 3/4)]
3205
+ sage: oc.reset_root_width(0, 1/2^200)
3206
+ sage: oc.find_roots()
3207
+ sage: oc
3208
+ ocean with precision 240 and 1 island(s)
3209
+ sage: RR(RealIntervalField(300)(oc.roots()[0]).absolute_diameter()).log2()
3210
+ -232.668979560890
3211
+ """
3212
+ cdef island isle = self.lgap.risland
3213
+ cdef int n = 0
3214
+ while isle is not self.endpoint:
3215
+ if n == isle_num:
3216
+ isle.reset_root_width(target_width)
3217
+
3218
+ isle = isle.rgap.risland
3219
+ n = n+1
3220
+
3221
+ def increase_precision(self):
3222
+ """
3223
+ Increase the precision of the interval Bernstein polynomial held
3224
+ by any islands which are not done. (In normal use, calls to this
3225
+ function are separated by calls to self.refine_all().)
3226
+
3227
+ EXAMPLES::
3228
+
3229
+ sage: from sage.rings.polynomial.real_roots import *
3230
+ sage: oc = ocean(mk_context(), bernstein_polynomial_factory_ratlist([1/3, -22/7, 193/71, -140/99]), lmap)
3231
+ sage: oc
3232
+ ocean with precision 120 and 1 island(s)
3233
+ sage: oc.increase_precision()
3234
+ sage: oc.increase_precision()
3235
+ sage: oc.increase_precision()
3236
+ sage: oc
3237
+ ocean with precision 960 and 1 island(s)
3238
+ """
3239
+ active_islands = []
3240
+ cdef int total_islands = 0
3241
+ cdef island isle = self.lgap.risland
3242
+ while isle is not self.endpoint:
3243
+ total_islands = total_islands + 1
3244
+ if not isle.done(self.ctx) and len(isle.ancestors) == 0:
3245
+ active_islands += [isle]
3246
+ isle = isle.rgap.risland
3247
+ if len(active_islands) > 0:
3248
+ self.prec = self.prec * 2
3249
+ p = self.approx_bp(self.msb - self.prec)
3250
+ targets = []
3251
+ for isle in active_islands:
3252
+ targets += [(isle.lgap, isle.rgap, isle.bp.scale_log2)]
3253
+ self.ctx.dc_log_append(('splitting', (isle.lgap.lower, isle.lgap.upper), (isle.rgap.lower, isle.rgap.upper), isle.bp.scale_log2))
3254
+ bps = split_for_targets(self.ctx, p, targets)
3255
+ for i in range(len(active_islands)):
3256
+ bp = bps[i]
3257
+ isle = active_islands[i]
3258
+ isle.bp = bp
3259
+
3260
+
3261
+ cdef class island:
3262
+ """
3263
+ This implements the island portion of my ocean-island root isolation
3264
+ algorithm. See the documentation for class ocean, for more
3265
+ information on the overall algorithm.
3266
+
3267
+ Island root refinement starts with a Bernstein polynomial whose
3268
+ region is the whole island (or perhaps slightly more than the
3269
+ island in certain cases). There are two subalgorithms; one when
3270
+ looking at a Bernstein polynomial covering a whole island (so we
3271
+ know that there are gaps on the left and right), and one when
3272
+ looking at a Bernstein polynomial covering the left segment of an
3273
+ island (so we know that there is a gap on the left, but the right
3274
+ is in the middle of an island). An important invariant of the
3275
+ left-segment subalgorithm over the region [l .. r] is that it
3276
+ always finds a gap [r0 .. r] ending at its right endpoint.
3277
+
3278
+ Ignoring degree reduction, downscaling (precision reduction), and
3279
+ failures to split, the algorithm is roughly:
3280
+
3281
+ Whole island:
3282
+
3283
+ 1. If the island definitely has exactly one root, then return.
3284
+ 2. Split the island in (approximately) half.
3285
+ 3. If both halves definitely have no roots, then remove this island from
3286
+ its doubly-linked list (merging its left and right gaps) and return.
3287
+ 4. If either half definitely has no roots, then discard that half
3288
+ and call the whole-island algorithm with the other half, then return.
3289
+ 5. If both halves may have roots, then call the left-segment algorithm
3290
+ on the left half.
3291
+ 6. We now know that there is a gap immediately to the left of the
3292
+ right half, so call the whole-island algorithm on the right half,
3293
+ then return.
3294
+
3295
+ Left segment:
3296
+
3297
+ 1. Split the left segment in (approximately) half.
3298
+ 2. If both halves definitely have no roots, then extend the left gap
3299
+ over the segment and return.
3300
+ 3. If the left half definitely has no roots, then extend the left gap
3301
+ over this half and call the left-segment algorithm on the right half,
3302
+ then return.
3303
+ 4. If the right half definitely has no roots, then split the island
3304
+ in two, creating a new gap. Call the whole-island algorithm on the
3305
+ left half, then return.
3306
+ 5. Both halves may have roots. Call the left-segment algorithm on
3307
+ the left half.
3308
+ 6. We now know that there is a gap immediately to the left of the
3309
+ right half, so call the left-segment algorithm on the right half,
3310
+ then return.
3311
+
3312
+ Degree reduction complicates this picture only slightly. Basically,
3313
+ we use heuristics to decide when degree reduction might be likely
3314
+ to succeed and be helpful; whenever this is the case, we attempt
3315
+ degree reduction.
3316
+
3317
+ Precision reduction and split failure add more complications.
3318
+ The algorithm maintains a stack of different-precision representations
3319
+ of the interval Bernstein polynomial. The base of the stack
3320
+ is at the highest (currently known) precision; each stack entry has
3321
+ approximately half the precision of the entry below it. When we
3322
+ do a split, we pop off the top of the stack, split it, then push
3323
+ whichever half we're interested in back on the stack (so the
3324
+ different Bernstein polynomials may be over different regions).
3325
+ When we push a polynomial onto the stack, we may heuristically decide to
3326
+ push further lower-precision versions of the same polynomial onto the
3327
+ stack.
3328
+
3329
+ In the algorithm above, whenever we say "split in (approximately) half",
3330
+ we attempt to split the top-of-stack polynomial using try_split()
3331
+ and try_rand_split(). However, these will fail if the sign of the
3332
+ polynomial at the chosen split point is unknown (if the polynomial is
3333
+ not known to high enough precision, or if the chosen split point
3334
+ actually happens to be a root of the polynomial). If this fails, then
3335
+ we discard the top-of-stack polynomial, and try again with the
3336
+ next polynomial down (which has approximately twice the precision).
3337
+ This next polynomial may not be over the same region; if not, we
3338
+ split it using de Casteljau's algorithm to get a polynomial over
3339
+ (approximately) the same region first.
3340
+
3341
+ If we run out of higher-precision polynomials (if we empty out the
3342
+ entire stack), then we give up on root refinement for this island.
3343
+ The ocean class will notice this, provide the island with a
3344
+ higher-precision polynomial, and restart root refinement. Basically
3345
+ the only information kept in that case is the lower and upper bounds
3346
+ on the island. Since these are updated whenever we discover a "half"
3347
+ (of an island or a segment) that definitely contains no roots, we
3348
+ never need to re-examine these gaps. (We could keep more information.
3349
+ For example, we could keep a record of split points that succeeded
3350
+ and failed. However, a split point that failed at lower precision
3351
+ is likely to succeed at higher precision, so it's not worth avoiding.
3352
+ It could be useful to select split points that are known to succeed,
3353
+ but starting from a new Bernstein polynomial over a slightly different
3354
+ region, hitting such split points would require de Casteljau splits
3355
+ with non-power-of-two denominators, which are much much slower.)
3356
+ """
3357
+
3358
+ def __init__(self, interval_bernstein_polynomial bp, rr_gap lgap, rr_gap rgap):
3359
+ """
3360
+ Initialize an island from a Bernstein polynomial, and the gaps to
3361
+ the left and right of the island.
3362
+ """
3363
+ self.bp = bp
3364
+ self.ancestors = []
3365
+ self.target_width = None
3366
+ self.lgap = lgap
3367
+ self.rgap = rgap
3368
+ self.known_done = False
3369
+
3370
+ lgap.risland = self
3371
+ rgap.lisland = self
3372
+
3373
+ def __repr__(self):
3374
+ """
3375
+ Return a short summary of this island.
3376
+ """
3377
+ return "island of width %s" % RR(self.bp.region_width())
3378
+
3379
+ def _info(self):
3380
+ # A python accessor for the information in this island.
3381
+ # For debugging purposes.
3382
+ return (self.bp, self.ancestors, self.target_width, self.lgap, self.rgap, self.known_done)
3383
+
3384
+ def shrink_bp(self, context ctx):
3385
+ """
3386
+ If the island's Bernstein polynomial covers a region much larger
3387
+ than the island itself (in particular, if either the island's
3388
+ left gap or right gap are totally contained in the polynomial's
3389
+ region) then shrink the polynomial down to cover the island more
3390
+ tightly.
3391
+ """
3392
+ while True:
3393
+ bounds = self.bp.region()
3394
+ lbounds = relative_bounds(bounds, self.lgap.region())
3395
+ rbounds = relative_bounds(bounds, self.rgap.region())
3396
+
3397
+ rtarget = wordsize_rational(rbounds[0], rbounds[1], ctx.wordsize)
3398
+ ltarget = wordsize_rational(lbounds[1], lbounds[0], ctx.wordsize)
3399
+
3400
+ if lbounds[0] > zero_QQ or (ltarget >= QQ_1_32 and ltarget >= one_QQ-rtarget):
3401
+ (_, self.bp, _) = self.bp.de_casteljau(ctx, ltarget)
3402
+ elif rbounds[1] < one_QQ or rtarget <= QQ_31_32:
3403
+ (self.bp, _, _) = self.bp.de_casteljau(ctx, rtarget)
3404
+ else:
3405
+ break
3406
+
3407
+ self.bp.lsign = self.lgap.sign
3408
+ self.bp.usign = self.rgap.sign
3409
+
3410
+ def refine(self, context ctx):
3411
+ """
3412
+ Attempts to shrink and/or split this island into sub-island
3413
+ that each definitely contain exactly one root.
3414
+ """
3415
+ self.shrink_bp(ctx)
3416
+ try:
3417
+ self.refine_recurse(ctx, self.bp, self.ancestors, [], True)
3418
+ except PrecisionError:
3419
+ pass
3420
+
3421
+ def refine_recurse(self, context ctx, interval_bernstein_polynomial bp, ancestors, history, rightmost):
3422
+ """
3423
+ This implements the root isolation algorithm described in the
3424
+ class documentation for class island. This is the implementation
3425
+ of both the whole-island and the left-segment algorithms;
3426
+ if the flag rightmost is True, then it is the whole-island algorithm,
3427
+ otherwise the left-segment algorithm.
3428
+
3429
+ The precision-reduction stack is (ancestors + [bp]); that is, the
3430
+ top-of-stack is maintained separately.
3431
+ """
3432
+ cdef interval_bernstein_polynomial p1, p2
3433
+ cdef rr_gap mgap
3434
+ cdef island lisland
3435
+
3436
+ # If you examine the description of this algorithm in the
3437
+ # class island class documentation, you see that several of
3438
+ # the calls involved are tail recursions (that is, they are
3439
+ # of the form "call (this algorithm) recursively, then return").
3440
+ # We perform tail-recursion optimization by hand: such calls
3441
+ # assign new values to the method parameters, and then fall off
3442
+ # the end of the following "while True" loop, and return to
3443
+ # the top of the method here.
3444
+
3445
+ # This optimization is VITAL; without it, several test polynomials
3446
+ # (in particular, polynomials with roots that are very, very
3447
+ # close together) give stack overflow errors.
3448
+
3449
+ while True:
3450
+ if rightmost and self.bp_done(bp):
3451
+ if bp.max_variations == 0:
3452
+ # No roots! Make the island disappear.
3453
+ self.lgap.risland = self.rgap.risland
3454
+ self.rgap.risland.lgap = self.lgap
3455
+ self.lgap.upper = self.rgap.upper
3456
+ else:
3457
+ self.bp = bp
3458
+ self.ancestors = ancestors
3459
+ return
3460
+
3461
+ # This is our heuristic for deciding when to do degree
3462
+ # reduction.
3463
+
3464
+ # In general, given a degree-d Bernstein polynomial,
3465
+ # if you perform a de Casteljau split at 1/2, the
3466
+ # coefficients of the resulting polynomials are about d bits
3467
+ # smaller than the coefficients of the original polynomial.
3468
+
3469
+ # Conversely, if you do a split and the coefficients are
3470
+ # k bits smaller than the coefficients of the original
3471
+ # polynomial, this indicates that the original polynomial
3472
+ # may be very close to some degree-k polynomial.
3473
+
3474
+ # Here, we look at the amount that the coefficients got smaller
3475
+ # over the last 3 splits. If they got more than 100 bits
3476
+ # smaller (that is, an average of more than 33 bits per split),
3477
+ # then we expect that the original polynomial is not
3478
+ # close to any polynomial of degree 30 or less. Since degree
3479
+ # reduction works by finding a polynomial of (currently)
3480
+ # degree 30 that is close to the original polynomial,
3481
+ # then this drastic reduction in coefficient size means that
3482
+ # degree reduction is likely to fail, so we don't bother
3483
+ # attempting it.
3484
+
3485
+ # Note that this does not take into account the effects of
3486
+ # random splitting; maybe it should? For example, if the
3487
+ # last three splits were random splits with split points near
3488
+ # 1/4, and we're in the left-hand branch of all these splits,
3489
+ # then we would expect twice as much coefficient reduction;
3490
+ # so a coefficient size drop of 100 bits would actually
3491
+ # mean that we are near a degree-17 polynomial.
3492
+
3493
+ # Also, we are willing to throw away up to 70 + msb_delta
3494
+ # bits of precision during degree reduction. I don't remember
3495
+ # how I selected this heuristic...
3496
+
3497
+ if len(history) >= 3:
3498
+ old = history[-3]
3499
+ old_msb = old.get_msb_bit()
3500
+ cur_msb = bp.get_msb_bit()
3501
+ msb_delta = old_msb - cur_msb
3502
+ if msb_delta <= 100 and bp.bitsize - msb_delta >= 70:
3503
+ bp = bp.down_degree_iter(ctx, bp.scale_log2 + 70 + msb_delta)
3504
+
3505
+ history = history[-3:] + [bp]
3506
+
3507
+ # Heuristically push more lower-precision polynomials
3508
+ # on the "ancestors" stack
3509
+ (ancestors, bp) = self.less_bits(ancestors, bp)
3510
+
3511
+ # Currently, we try a random split only once before giving up
3512
+ # and trying for higher precision; and then we try a 1/2 split
3513
+ # at the higher precision. Maybe we should try more random
3514
+ # splits before going to higher precision? Maybe we should
3515
+ # try less 1/2 splits?
3516
+ rv = bp.try_split(ctx, [])
3517
+ while rv is None:
3518
+ if bp.bitsize > 30:
3519
+ rv = bp.try_rand_split(ctx, [])
3520
+ if rv is None:
3521
+ (ancestors, bp) = self.more_bits(ctx, ancestors, bp, rightmost)
3522
+ if rv is None:
3523
+ rv = bp.try_split(ctx, [])
3524
+
3525
+ (p1_, p2_, _) = rv
3526
+ p1 = p1_
3527
+ p2 = p2_
3528
+
3529
+ # ctx.dc_log_append(('split_results', p1.variations(), p2.variations()))
3530
+
3531
+ if p1.variations()[1] == 0:
3532
+ self.lgap.upper = p2.lower
3533
+ if p2.variations()[1] == 0:
3534
+ if rightmost:
3535
+ # No roots! Make the island disappear.
3536
+ self.lgap.risland = self.rgap.risland
3537
+ self.rgap.risland.lgap = self.lgap
3538
+ self.lgap.upper = self.rgap.upper
3539
+ return
3540
+ self.lgap.upper = p2.upper
3541
+ return
3542
+ else:
3543
+ bp = p2
3544
+ # return to top of function (tail recursion optimization)
3545
+ else:
3546
+ if p2.variations()[1] == 0:
3547
+ if rightmost:
3548
+ self.rgap.lower = p2.lower
3549
+ bp = p1
3550
+ # return to top of function
3551
+ else:
3552
+ # Split the island!
3553
+ mgap = rr_gap(p2.lower, p2.upper, p2.lsign)
3554
+ lisland = island(p1, self.lgap, mgap)
3555
+ lisland.target_width = self.target_width
3556
+ self.lgap = mgap
3557
+ mgap.risland = self
3558
+ if not lisland.done(ctx):
3559
+ try:
3560
+ lisland.refine_recurse(ctx, p1, ancestors, history, True)
3561
+ except PrecisionError:
3562
+ pass
3563
+ return
3564
+ else:
3565
+ self.refine_recurse(ctx, p1, ancestors, history, False)
3566
+ assert self.lgap.upper == p2.lower
3567
+ bp = p2
3568
+ # return to top of function (tail recursion optimization)
3569
+
3570
+ def less_bits(self, ancestors, interval_bernstein_polynomial bp):
3571
+ """
3572
+ Heuristically push lower-precision polynomials on
3573
+ the polynomial stack. See the class documentation for class
3574
+ island for more information.
3575
+ """
3576
+ # The current heuristic is to always push one lower-precision
3577
+ # polynomial, unless the current polynomial is floating-point.
3578
+ # If the current polynomial has bitsize < 130, then the new
3579
+ # polynomial is floating-point, otherwise it is integer,
3580
+ # with half the precision of the original.
3581
+
3582
+ if bp.bitsize < 130:
3583
+ if isinstance(bp, interval_bernstein_polynomial_float):
3584
+ return (ancestors, bp)
3585
+ else:
3586
+ return (ancestors + [bp], bp.as_float())
3587
+ else:
3588
+ return (ancestors + [bp], bp.downscale(bp.bitsize // 2))
3589
+
3590
+ def more_bits(self, context ctx, ancestors, interval_bernstein_polynomial bp, rightmost):
3591
+ """
3592
+ Find a Bernstein polynomial on the "ancestors" stack with
3593
+ more precision than bp; if it is over a different region,
3594
+ then shrink its region to (approximately) match that of bp.
3595
+ (If this is rightmost -- if bp covers the whole island -- then
3596
+ we only require that the new region cover the whole island
3597
+ fairly tightly; if this is not rightmost, then the new region
3598
+ will have exactly the same right boundary as bp, although the
3599
+ left boundary may vary slightly.)
3600
+ """
3601
+ cur_msb = bp.scale_log2 + bp.bitsize
3602
+ extra_bits = bp.bitsize // 2
3603
+ if extra_bits < 30:
3604
+ extra_bits = 30
3605
+
3606
+ target_lsb_h = cur_msb - 3*extra_bits
3607
+ target_lsb = cur_msb - 4*extra_bits
3608
+ target_lsb_l = cur_msb - 6*extra_bits
3609
+
3610
+ if bp.bitsize < 32:
3611
+ target_lsb_h = cur_msb - 48
3612
+ target_lsb = target_lsb_h - 16
3613
+ target_lsb_l = target_lsb - 32
3614
+
3615
+ cdef interval_bernstein_polynomial anc
3616
+ cdef interval_bernstein_polynomial ancestor_val
3617
+
3618
+ for i in range(len(ancestors)-1, -1, -1):
3619
+ anc = ancestors[i]
3620
+ if target_lsb_h >= anc.scale_log2:
3621
+ ancestor_val = anc
3622
+ first_lsb = ancestor_val.scale_log2
3623
+ first_msb = first_lsb + ancestor_val.bitsize
3624
+
3625
+ ancestors = ancestors[:i]
3626
+
3627
+ if bp.region() == ancestor_val.region():
3628
+ if bp.bitsize < 32:
3629
+ return (ancestors + [ancestor_val], ancestor_val.as_float())
3630
+ else:
3631
+ return (ancestors, ancestor_val)
3632
+
3633
+ new_lsb = ancestor_val.scale_log2
3634
+ if new_lsb < target_lsb_l:
3635
+ new_lsb = target_lsb
3636
+
3637
+ hv_width = ancestor_val.region_width()
3638
+ rel_bounds = relative_bounds(ancestor_val.region(), bp.region())
3639
+ rel_width = rel_bounds[1] - rel_bounds[0]
3640
+
3641
+ rel_width_rr = RR(rel_width)
3642
+
3643
+ ctx.dc_log_append(('pulling',
3644
+ first_msb,
3645
+ ancestor_val.level,
3646
+ first_lsb,
3647
+ ancestor_val.scale_log2,
3648
+ rel_width_rr,
3649
+ new_lsb,
3650
+ cur_msb, bp.scale_log2,
3651
+ target_lsb_h, target_lsb, target_lsb_l))
3652
+
3653
+ if rightmost:
3654
+ maybe_rgap = self.rgap
3655
+ else:
3656
+ maybe_rgap = None
3657
+ if rel_bounds[1] < 1:
3658
+ (ancestor_val, _, _) = ancestor_val.de_casteljau(ctx, rel_bounds[1])
3659
+ ctx.dc_log_append(('pull_right', rel_bounds[1]))
3660
+ if ancestor_val.region_width() / hv_width < ~Integer(32):
3661
+ ancestor_val = ancestor_val.down_degree_iter(ctx, target_lsb_h)
3662
+
3663
+ rel_bounds = relative_bounds(ancestor_val.region(), bp.region())
3664
+ assert rel_bounds[1] == 1
3665
+
3666
+ ancestor_val = split_for_targets(ctx, ancestor_val, [(self.lgap, maybe_rgap, target_lsb_h)])[0]
3667
+ # if rel_lbounds[1] > 0:
3668
+ # left_split = -exact_rational(simple_wordsize_float(-rel_lbounds[1], -rel_lbounds[0]))
3669
+ # (_, ancestor_val, _) = ancestor_val.de_casteljau(ctx, left_split)
3670
+ # ctx.dc_log_append(('pull_left', left_split))
3671
+
3672
+ ancestor_val.lsign = bp.lsign
3673
+ ancestor_val.usign = bp.usign
3674
+
3675
+ new_rel_bounds = relative_bounds(ancestor_val.region(), bp.region())
3676
+ assert new_rel_bounds[1] - new_rel_bounds[0] >= Integer(255)/256
3677
+
3678
+ while ancestor_val.scale_log2 < target_lsb_l:
3679
+ ancestors = ancestors + [ancestor_val]
3680
+ ancestor_val = ancestor_val.downscale(ancestor_val.bitsize // 2)
3681
+
3682
+ if bp.bitsize < 32:
3683
+ return (ancestors + [ancestor_val], ancestor_val.as_float())
3684
+
3685
+ return (ancestors, ancestor_val)
3686
+
3687
+ self.ancestors = []
3688
+ raise PrecisionError()
3689
+
3690
+ def reset_root_width(self, target_width):
3691
+ """
3692
+ Modify the criteria for this island to require that it is not "done"
3693
+ until its width is less than or equal to target_width.
3694
+ """
3695
+
3696
+ width = self.bp.upper - self.bp.lower
3697
+
3698
+ if target_width < width:
3699
+ self.known_done = False
3700
+
3701
+ if self.target_width is None or target_width < self.target_width:
3702
+ self.target_width = target_width
3703
+
3704
+ def bp_done(self, interval_bernstein_polynomial bp):
3705
+ """
3706
+ Examine the given Bernstein polynomial to see if it is known
3707
+ to have exactly one root in its region. (In addition, we require
3708
+ that the polynomial region not include 0 or 1. This makes things
3709
+ work if the user gives explicit bounds to real_roots(),
3710
+ where the lower or upper bound is a root of the polynomial.
3711
+ real_roots() deals with this by explicitly detecting it,
3712
+ dividing out the appropriate linear polynomial, and adding the
3713
+ root to the returned list of roots; but then if the island
3714
+ considers itself "done" with a region including 0 or 1, the returned
3715
+ root regions can overlap with each other.)
3716
+ """
3717
+
3718
+ variations = bp.variations()[1]
3719
+
3720
+ if variations > 1:
3721
+ return False
3722
+ if bp.lower == 0:
3723
+ return False
3724
+ if bp.upper == 1:
3725
+ return False
3726
+ if variations == 0:
3727
+ return True
3728
+ if self.target_width is not None and self.bp.upper - self.bp.lower > self.target_width:
3729
+ return False
3730
+ if bp.level == 0:
3731
+ return True
3732
+ if not (0 in bp.slope_err + bp.slope_range()):
3733
+ return True
3734
+ return False
3735
+
3736
+ def done(self, context ctx):
3737
+ """
3738
+ Check to see if the island is known to contain zero roots or
3739
+ is known to contain one root.
3740
+ """
3741
+
3742
+ if self.known_done:
3743
+ return True
3744
+
3745
+ if self.bp_done(self.bp):
3746
+ self.known_done = True
3747
+ else:
3748
+ self.shrink_bp(ctx)
3749
+ if self.bp_done(self.bp):
3750
+ self.known_done = True
3751
+
3752
+ return self.known_done
3753
+
3754
+ def has_root(self) -> bool:
3755
+ """
3756
+ Assuming that the island is done (has either 0 or 1 roots),
3757
+ reports whether the island has a root.
3758
+ """
3759
+ assert self.known_done
3760
+
3761
+ return bool(self.bp.max_variations)
3762
+
3763
+
3764
+ cdef class rr_gap:
3765
+ """
3766
+ A simple class representing the gaps between islands, in my
3767
+ ocean-island root isolation algorithm. Named "rr_gap" for
3768
+ "real roots gap", because "gap" seemed too short and generic.
3769
+ """
3770
+
3771
+ def __init__(self, lower, upper, sign):
3772
+ """
3773
+ Initialize an rr_gap element.
3774
+ """
3775
+ self.lower = lower
3776
+ self.upper = upper
3777
+ self.sign = sign
3778
+
3779
+ def region(self):
3780
+ return (self.lower, self.upper)
3781
+
3782
+
3783
+ class linear_map:
3784
+ """
3785
+ A simple class to map linearly between original coordinates
3786
+ (ranging from [lower .. upper]) and ocean coordinates (ranging
3787
+ from [0 .. 1]).
3788
+ """
3789
+
3790
+ def __init__(self, lower, upper):
3791
+ self.lower = lower
3792
+ self.upper = upper
3793
+ self.width = upper - lower
3794
+
3795
+ def from_ocean(self, region):
3796
+ (l, u) = region
3797
+ return (self.lower + l*self.width, self.lower + u*self.width)
3798
+
3799
+ def to_ocean(self, region):
3800
+ (l, u) = region
3801
+ return ((l - self.lower) / self.width, (u - self.lower) / self.width)
3802
+
3803
+
3804
+ lmap = linear_map(0, 1)
3805
+
3806
+
3807
+ class warp_map:
3808
+ """
3809
+ A class to map between original coordinates and ocean coordinates.
3810
+ If neg is False, then the original->ocean transform is
3811
+ x -> x/(x+1), and the ocean->original transform is x/(1-x);
3812
+ this maps between [0 .. infinity] and [0 .. 1].
3813
+ If neg is True, then the original->ocean transform is
3814
+ x -> -x/(1-x), and the ocean->original transform is the same thing:
3815
+ -x/(1-x). This maps between [0 .. -infinity] and [0 .. 1].
3816
+ """
3817
+
3818
+ def __init__(self, neg):
3819
+ self.neg = neg
3820
+
3821
+ def from_ocean(self, region):
3822
+ (l, u) = region
3823
+ if self.neg:
3824
+ return (-u/(1-u), -l/(1-l))
3825
+ else:
3826
+ return (l/(1-l), u/(1-u))
3827
+
3828
+ def to_ocean(self, region):
3829
+ (l, u) = region
3830
+ if self.neg:
3831
+ return (-u/(1-u), -l/(1-l))
3832
+ else:
3833
+ return (l/(l+1), u/(u+1))
3834
+
3835
+
3836
+ def real_roots(p, bounds=None, seed=None, skip_squarefree=False, do_logging=False, wordsize=32, retval='rational', strategy=None, max_diameter=None):
3837
+ """
3838
+ Compute the real roots of a given polynomial with exact coefficients
3839
+ (integer, rational, and algebraic real coefficients are supported).
3840
+
3841
+ This returns a list of pairs of a root and its multiplicity.
3842
+
3843
+ The root itself can be returned in one of three different ways.
3844
+ If retval=='rational', then it is returned as a pair of rationals
3845
+ that define a region that includes exactly one root. If
3846
+ retval=='interval', then it is returned as a RealIntervalFieldElement
3847
+ that includes exactly one root. If retval=='algebraic_real', then
3848
+ it is returned as an AlgebraicReal. In the former two cases, all
3849
+ the intervals are disjoint.
3850
+
3851
+ An alternate high-level algorithm can be used by selecting
3852
+ strategy='warp'. This affects the conversion into Bernstein
3853
+ polynomial form, but still uses the same ocean-island algorithm
3854
+ as the default algorithm. The 'warp' algorithm performs the conversion
3855
+ into Bernstein polynomial form much more quickly, but performs
3856
+ the rest of the computation slightly slower in some benchmarks.
3857
+ The 'warp' algorithm is particularly likely to be helpful for
3858
+ low-degree polynomials.
3859
+
3860
+ Part of the algorithm is randomized; the seed parameter gives a seed
3861
+ for the random number generator. (By default, the same
3862
+ seed is used for every call, so that results are repeatable.) The
3863
+ random seed may affect the running time, or the exact intervals returned,
3864
+ but the results are correct regardless of the seed used.
3865
+
3866
+ The bounds parameter lets you find roots in some proper subinterval of
3867
+ the reals; it takes a pair of a rational lower and upper bound
3868
+ and only roots within this bound will be found. Currently, specifying
3869
+ bounds does not work if you select strategy='warp', or if you
3870
+ use a polynomial with algebraic real coefficients.
3871
+
3872
+ By default, the algorithm will do a squarefree decomposition
3873
+ to get squarefree polynomials. The skip_squarefree parameter
3874
+ lets you skip this step. (If this step is skipped, and the polynomial
3875
+ has a repeated real root, then the algorithm will loop forever!
3876
+ However, repeated non-real roots are not a problem.)
3877
+
3878
+ For integer and rational coefficients, the squarefree
3879
+ decomposition is very fast, but it may be slow for algebraic
3880
+ reals. (It may trigger exact computation, so it might be
3881
+ arbitrarily slow. The only other way that this algorithm might
3882
+ trigger exact computation on algebraic real coefficients is that
3883
+ it checks the constant term of the input polynomial for equality with
3884
+ zero.)
3885
+
3886
+ Part of the algorithm works (approximately) by splitting numbers into
3887
+ word-size pieces (that is, pieces that fit into a machine word).
3888
+ For portability, this defaults to always selecting pieces suitable
3889
+ for a 32-bit machine; the wordsize parameter lets you make choices
3890
+ suitable for a 64-bit machine instead. (This affects the running
3891
+ time, and the exact intervals returned, but the results are correct
3892
+ on both 32- and 64-bit machines even if the wordsize is chosen "wrong".)
3893
+
3894
+ The precision of the results can be improved (at the expense of time,
3895
+ of course) by specifying the max_diameter parameter. If specified,
3896
+ this sets the maximum diameter() of the intervals returned.
3897
+ (Sage defines diameter() to be the relative diameter for intervals
3898
+ that do not contain 0, and the absolute diameter for intervals
3899
+ containing 0.) This directly affects the results in rational or
3900
+ interval return mode; in algebraic_real mode, it increases the
3901
+ precision of the intervals passed to the algebraic number package,
3902
+ which may speed up some operations on that algebraic real.
3903
+
3904
+ Some logging can be enabled with do_logging=True. If logging is enabled,
3905
+ then the normal values are not returned; instead, a pair of
3906
+ the internal context object and a list of all the roots in their
3907
+ internal form is returned.
3908
+
3909
+ ALGORITHM: We convert the polynomial into the Bernstein basis, and
3910
+ then use de Casteljau's algorithm and Descartes' rule of signs
3911
+ (using interval arithmetic) to locate the roots.
3912
+
3913
+ EXAMPLES::
3914
+
3915
+ sage: from sage.rings.polynomial.real_roots import *
3916
+ sage: x = polygen(ZZ)
3917
+ sage: real_roots(x^3 - x^2 - x - 1)
3918
+ [((7/4, 19/8), 1)]
3919
+ sage: real_roots((x-1)*(x-2)*(x-3)*(x-5)*(x-8)*(x-13)*(x-21)*(x-34))
3920
+ [((11/16, 33/32), 1), ((11/8, 33/16), 1), ((11/4, 55/16), 1), ((77/16, 165/32), 1), ((11/2, 33/4), 1), ((11, 55/4), 1), ((165/8, 341/16), 1), ((22, 44), 1)]
3921
+ sage: real_roots(x^5 * (x^2 - 9999)^2 - 1)
3922
+ [((-29274496381311/9007199254740992, 419601125186091/2251799813685248), 1), ((2126658450145849453951061654415153249597/21267647932558653966460912964485513216, 4253316902721330018853696359533061621799/42535295865117307932921825928971026432), 1), ((1063329226287740282451317352558954186101/10633823966279326983230456482242756608, 531664614358685696701445201630854654353/5316911983139663491615228241121378304), 1)]
3923
+ sage: real_roots(x^5 * (x^2 - 9999)^2 - 1, seed=42)
3924
+ [((-123196838480289/18014398509481984, 293964743458749/9007199254740992), 1), ((8307259573979551907841696381986376143/83076749736557242056487941267521536, 16614519150981033789137940378745325503/166153499473114484112975882535043072), 1), ((519203723562592617581015249797434335/5192296858534827628530496329220096, 60443268924081068060312183/604462909807314587353088), 1)]
3925
+ sage: real_roots(x^5 * (x^2 - 9999)^2 - 1, wordsize=64)
3926
+ [((-62866503803202151050003/19342813113834066795298816, 901086554512564177624143/4835703278458516698824704), 1), ((544424563237337315214990987922809050101157/5444517870735015415413993718908291383296, 1088849127096660194637118845654929064385439/10889035741470030830827987437816582766592), 1), ((272212281929661439711063928866060007142141/2722258935367507707706996859454145691648, 136106141275823501959100399337685485662633/1361129467683753853853498429727072845824), 1)]
3927
+ sage: real_roots(x)
3928
+ [((-47/256, 81/512), 1)]
3929
+ sage: real_roots(x * (x-1))
3930
+ [((-47/256, 81/512), 1), ((1/2, 1201/1024), 1)]
3931
+ sage: real_roots(x-1)
3932
+ [((209/256, 593/512), 1)]
3933
+ sage: real_roots(x*(x-1)*(x-2), bounds=(0, 2))
3934
+ [((0, 0), 1), ((81/128, 337/256), 1), ((2, 2), 1)]
3935
+ sage: real_roots(x*(x-1)*(x-2), bounds=(0, 2), retval='algebraic_real')
3936
+ [(0, 1), (1, 1), (2, 1)]
3937
+ sage: v = 2^40
3938
+ sage: real_roots((x^2-1)^2 * (x^2 - (v+1)/v))
3939
+ [((-12855504354077768210885019021174120740504020581912910106032833/12855504354071922204335696738729300820177623950262342682411008, -6427752177038884105442509510587059395588605840418680645585479/6427752177035961102167848369364650410088811975131171341205504), 1), ((-1125899906842725/1125899906842624, -562949953421275/562949953421312), 2), ((62165404551223330269422781018352603934643403586760330761772204409982940218804935733653/62165404551223330269422781018352605012557018849668464680057997111644937126566671941632, 3885337784451458141838923813647037871787041539340705594199885610069035709862106085785/3885337784451458141838923813647037813284813678104279042503624819477808570410416996352), 2), ((509258994083853105745586001837045839749063767798922046787130823804169826426726965449697819/509258994083621521567111422102344540262867098416484062659035112338595324940834176545849344, 25711008708155536421770038042348240136257704305733983563630791/25711008708143844408671393477458601640355247900524685364822016), 1)]
3940
+ sage: real_roots(x^2 - 2)
3941
+ [((-3/2, -1), 1), ((1, 3/2), 1)]
3942
+ sage: real_roots(x^2 - 2, retval='interval')
3943
+ [(-2.?, 1), (2.?, 1)]
3944
+ sage: real_roots(x^2 - 2, max_diameter=1/2^30)
3945
+ [((-22506280506048041472675379598886543645348790970912519198456805737131269246430553365310109/15914343565113172548972231940698266883214596825515126958094847260581103904401068017057792, -45012561012096082945350759197773086524448972309421182031053065599548946985601579935498343/31828687130226345097944463881396533766429193651030253916189694521162207808802136034115584), 1), ((45012561012096082945350759197773086524448972309421182031053065599548946985601579935498343/31828687130226345097944463881396533766429193651030253916189694521162207808802136034115584, 22506280506048041472675379598886543645348790970912519198456805737131269246430553365310109/15914343565113172548972231940698266883214596825515126958094847260581103904401068017057792), 1)]
3946
+ sage: real_roots(x^2 - 2, retval='interval', max_diameter=1/2^500)
3947
+ [(-1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641572735013846230912297024924836055850737212644121497099935831413222665927505592755799950501152782060571470109559971605970274534596862014728517418640889198609552?, 1), (1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641572735013846230912297024924836055850737212644121497099935831413222665927505592755799950501152782060571470109559971605970274534596862014728517418640889198609552?, 1)]
3948
+ sage: ar_rts = real_roots(x^2 - 2, retval='algebraic_real'); ar_rts
3949
+ [(-1.414213562373095?, 1), (1.414213562373095?, 1)]
3950
+ sage: ar_rts[0][0]^2 - 2 == 0
3951
+ True
3952
+ sage: v = 2^40
3953
+ sage: real_roots((x-1) * (x-(v+1)/v), retval='interval')
3954
+ [(1.000000000000?, 1), (1.000000000001?, 1)]
3955
+ sage: v = 2^60
3956
+ sage: real_roots((x-1) * (x-(v+1)/v), retval='interval')
3957
+ [(1.000000000000000000?, 1), (1.000000000000000001?, 1)]
3958
+ sage: real_roots((x-1) * (x-2), strategy='warp')
3959
+ [((499/525, 1173/875), 1), ((337/175, 849/175), 1)]
3960
+ sage: real_roots((x+3)*(x+1)*x*(x-1)*(x-2), strategy='warp')
3961
+ [((-1713/335, -689/335), 1), ((-2067/2029, -689/1359), 1), ((0, 0), 1), ((499/525, 1173/875), 1), ((337/175, 849/175), 1)]
3962
+ sage: real_roots((x+3)*(x+1)*x*(x-1)*(x-2), strategy='warp', retval='algebraic_real')
3963
+ [(-3.000000000000000?, 1), (-1.000000000000000?, 1), (0, 1), (1.000000000000000?, 1), (2.000000000000000?, 1)]
3964
+ sage: ar_rts = real_roots(x-1, retval='algebraic_real')
3965
+ sage: ar_rts[0][0] == 1
3966
+ True
3967
+
3968
+ If the polynomial has no real roots, we get an empty list.
3969
+
3970
+ ::
3971
+
3972
+ sage: (x^2 + 1).real_root_intervals()
3973
+ []
3974
+
3975
+ We can compute Conway's constant
3976
+ (see http://mathworld.wolfram.com/ConwaysConstant.html) to arbitrary
3977
+ precision. ::
3978
+
3979
+ sage: p = x^71 - x^69 - 2*x^68 - x^67 + 2*x^66 + 2*x^65 + x^64 - x^63 - x^62 - x^61 - x^60 - x^59 + 2*x^58 + 5*x^57 + 3*x^56 - 2*x^55 - 10*x^54 - 3*x^53 - 2*x^52 + 6*x^51 + 6*x^50 + x^49 + 9*x^48 - 3*x^47 - 7*x^46 - 8*x^45 - 8*x^44 + 10*x^43 + 6*x^42 + 8*x^41 - 5*x^40 - 12*x^39 + 7*x^38 - 7*x^37 + 7*x^36 + x^35 - 3*x^34 + 10*x^33 + x^32 - 6*x^31 - 2*x^30 - 10*x^29 - 3*x^28 + 2*x^27 + 9*x^26 - 3*x^25 + 14*x^24 - 8*x^23 - 7*x^21 + 9*x^20 + 3*x^19 - 4*x^18 - 10*x^17 - 7*x^16 + 12*x^15 + 7*x^14 + 2*x^13 - 12*x^12 - 4*x^11 - 2*x^10 + 5*x^9 + x^7 - 7*x^6 + 7*x^5 - 4*x^4 + 12*x^3 - 6*x^2 + 3*x - 6
3980
+ sage: cc = real_roots(p, retval='algebraic_real')[2][0] # long time
3981
+ sage: RealField(180)(cc) # long time
3982
+ 1.3035772690342963912570991121525518907307025046594049
3983
+
3984
+ Now we play with algebraic real coefficients. ::
3985
+
3986
+ sage: x = polygen(AA)
3987
+ sage: p = (x - 1) * (x - sqrt(AA(2))) * (x - 2)
3988
+ sage: real_roots(p)
3989
+ [((499/525, 2171/1925), 1), ((1173/875, 2521/1575), 1), ((337/175, 849/175), 1)]
3990
+ sage: ar_rts = real_roots(p, retval='algebraic_real'); ar_rts
3991
+ [(1.000000000000000?, 1), (1.414213562373095?, 1), (2.000000000000000?, 1)]
3992
+ sage: ar_rts[1][0]^2 == 2
3993
+ True
3994
+ sage: ar_rts = real_roots(x*(x-1), retval='algebraic_real')
3995
+ sage: ar_rts[0][0] == 0
3996
+ True
3997
+ sage: p2 = p * (p - 1/100); p2
3998
+ x^6 - 8.82842712474619?*x^5 + 31.97056274847714?*x^4 - 60.77955262170047?*x^3 + 63.98526763257801?*x^2 - 35.37613490585595?*x + 8.028284271247462?
3999
+ sage: real_roots(p2, retval='interval')
4000
+ [(1.00?, 1), (1.1?, 1), (1.38?, 1), (1.5?, 1), (2.00?, 1), (2.1?, 1)]
4001
+ sage: p = (x - 1) * (x - sqrt(AA(2)))^2 * (x - 2)^3 * sqrt(AA(3))
4002
+ sage: real_roots(p, retval='interval')
4003
+ [(1.000000000000000?, 1), (1.414213562373095?, 2), (2.000000000000000?, 3)]
4004
+
4005
+ TESTS:
4006
+
4007
+ Check that :issue:`20269` is fixed::
4008
+
4009
+ sage: real_roots(polygen(AA))[0][0][0].parent()
4010
+ Rational Field
4011
+
4012
+ Check that :issue:`10803` is fixed::
4013
+
4014
+ sage: f = 2503841067*x^13 - 15465014877*x^12 + 37514382885*x^11 - 44333754994*x^10 + 24138665092*x^9 - 2059014842*x^8 - 3197810701*x^7 + 803983752*x^6 + 123767204*x^5 - 26596986*x^4 - 2327140*x^3 + 75923*x^2 + 7174*x + 102
4015
+ sage: len(real_roots(f,seed=1))
4016
+ 13
4017
+ """
4018
+ base = p.base_ring()
4019
+
4020
+ ar_input = False
4021
+
4022
+ if base is not ZZ:
4023
+ ZZx = PolynomialRing(ZZ, 'x')
4024
+ if base is QQ:
4025
+ p = ZZx(p * p.denominator())
4026
+ elif base is AA:
4027
+ ar_input = True
4028
+ else:
4029
+ raise ValueError("Don't know how to isolate roots for " + str(p.parent()))
4030
+
4031
+ if ar_input and bounds is not None:
4032
+ raise NotImplementedError("Cannot set your own bounds with algebraic real input")
4033
+
4034
+ if ar_input:
4035
+ strategy = 'warp'
4036
+
4037
+ if bounds is not None and strategy == 'warp':
4038
+ raise NotImplementedError("Cannot set your own bounds with strategy=warp")
4039
+
4040
+ if seed is None:
4041
+ seed = 1
4042
+
4043
+ if skip_squarefree:
4044
+ factors = [(p, 1)]
4045
+ else:
4046
+ factors = p.squarefree_decomposition()
4047
+
4048
+ if max_diameter is not None:
4049
+ max_diameter = QQ(max_diameter)
4050
+
4051
+ ctx = context(do_logging, seed, wordsize)
4052
+
4053
+ extra_roots = []
4054
+ oceans = []
4055
+
4056
+ cdef ocean oc
4057
+
4058
+ for factor, exp in factors:
4059
+ if strategy=='warp':
4060
+ if factor.constant_coefficient() == 0:
4061
+ x = factor.parent().gen()
4062
+ extra_roots.append(((QQ.zero(), QQ.zero()), x, exp, None, None))
4063
+ factor = factor // x
4064
+ if ar_input:
4065
+ oc = ocean(ctx, bernstein_polynomial_factory_ar(factor, False), warp_map(False))
4066
+ else:
4067
+ b = to_bernstein_warp(factor)
4068
+ oc = ocean(ctx, bernstein_polynomial_factory_ratlist(b), warp_map(False))
4069
+ oc.find_roots()
4070
+ oceans.append((oc, factor, exp))
4071
+
4072
+ if ar_input:
4073
+ oc = ocean(ctx, bernstein_polynomial_factory_ar(factor, True), warp_map(True))
4074
+ else:
4075
+ b = copy(b)
4076
+ for i in range(1, len(b), 2):
4077
+ b[i] = -b[i]
4078
+ oc = ocean(ctx, bernstein_polynomial_factory_ratlist(b), warp_map(True))
4079
+ oc.find_roots()
4080
+ oceans.append((oc, factor, exp))
4081
+ else:
4082
+ if bounds is None:
4083
+ fac_bounds = rational_root_bounds(factor)
4084
+ if fac_bounds is None:
4085
+ continue
4086
+ else:
4087
+ (left, right) = fac_bounds
4088
+ else:
4089
+ (left, right) = bounds
4090
+ # Bad things happen if the bounds are roots themselves.
4091
+ # Avoid this by dividing out linear polynomials if
4092
+ # the bounds are roots.
4093
+ if factor(left) == 0:
4094
+ x = factor.parent().gen()
4095
+ linfac = (x * left.denominator() - left.numerator())
4096
+ extra_roots.append(((left, left), linfac, exp, None, None))
4097
+ factor = factor // linfac
4098
+ if factor(right) == 0:
4099
+ x = factor.parent().gen()
4100
+ linfac = (x * right.denominator() - right.numerator())
4101
+ extra_roots.append(((right, right), linfac, exp, None, None))
4102
+ factor = factor // linfac
4103
+
4104
+ b, _ = to_bernstein(factor, left, right)
4105
+
4106
+ oc = ocean(ctx, bernstein_polynomial_factory_ratlist(b), linear_map(left, right))
4107
+ oc.find_roots()
4108
+ oceans.append((oc, factor, exp))
4109
+
4110
+ while True:
4111
+ all_roots = copy(extra_roots)
4112
+
4113
+ for oc, factor, exp in oceans:
4114
+ rel_roots = oc.roots()
4115
+
4116
+ cur_roots = [oc.mapping.from_ocean(r) for r in rel_roots]
4117
+
4118
+ all_roots.extend([(cur_roots[j], factor, exp, oc, j) for j in range(len(cur_roots))])
4119
+
4120
+ all_roots.sort()
4121
+
4122
+ ok = True
4123
+
4124
+ target_widths = [None] * len(all_roots)
4125
+
4126
+ if max_diameter is not None:
4127
+ # Check to make sure that no intervals are too wide.
4128
+
4129
+ # We use half_diameter, because if we ended up with a rational
4130
+ # interval that was exactly max_diameter, we might not
4131
+ # be able to coerce it into an interval small enough.
4132
+ half_diameter = max_diameter/2
4133
+
4134
+ for i in range(len(all_roots)):
4135
+ root = all_roots[i][0]
4136
+ if (root[0] <= 0) and (root[1] >= 0):
4137
+ cur_diam = root[1] - root[0]
4138
+ if cur_diam > half_diameter:
4139
+ target_widths[i] = half_diameter
4140
+ ok = False
4141
+ else:
4142
+ cur_diam = (root[1] - root[0]) / abs((root[0] + root[1]) / 2)
4143
+ if cur_diam > half_diameter:
4144
+ target_widths[i] = (root[1] - root[0]) / cur_diam * half_diameter
4145
+ ok = False
4146
+
4147
+ for i in range(len(all_roots) - 1):
4148
+ # Check to be sure that all intervals are disjoint.
4149
+ if all_roots[i][0][1] >= all_roots[i+1][0][0]:
4150
+ ok = False
4151
+ cur_width = max(all_roots[i+1][0][1] - all_roots[i+1][0][0], all_roots[i][0][1] - all_roots[i][0][0])
4152
+ target_width = cur_width/16
4153
+ target_widths[i] = target_width
4154
+ target_widths[i+1] = target_width
4155
+
4156
+ for i in range(len(all_roots)):
4157
+ if target_widths[i] is not None:
4158
+ root = all_roots[i][0]
4159
+ oc = all_roots[i][3]
4160
+ target_region = (root[0], root[0] + target_widths[i])
4161
+ if target_region[0] <= 0 and target_region[1] >= 0:
4162
+ target_region = (root[1] - target_widths[i], root[1])
4163
+
4164
+ ocean_target = oc.mapping.to_ocean(target_region)
4165
+ oc.reset_root_width(all_roots[i][4], ocean_target[1] - ocean_target[0])
4166
+
4167
+ if ok:
4168
+ break
4169
+
4170
+ for oc, factor, exp in oceans:
4171
+ oc.find_roots()
4172
+
4173
+ if do_logging:
4174
+ return ctx, all_roots
4175
+
4176
+ if retval == 'rational':
4177
+ return [(r[0], r[2]) for r in all_roots]
4178
+
4179
+ for i in range(1000):
4180
+ intv_bits = 53 << i
4181
+ intv_fld = RealIntervalField(intv_bits)
4182
+ intv_roots = [(intv_fld(r[0]), r[1], r[2], r[3], r[4]) for r in all_roots]
4183
+ ok = True
4184
+
4185
+ if max_diameter is not None:
4186
+ for rt in intv_roots:
4187
+ if rt[0].diameter() > max_diameter:
4188
+ ok = False
4189
+
4190
+ for j in range(len(intv_roots) - 1):
4191
+ # The following line should work, but does not due to a Cython
4192
+ # bug (it calls PyObject_Cmp() for comparison operators,
4193
+ # instead of PyObject_RichCompare()).
4194
+
4195
+ # if not (intv_roots[j][0] < intv_roots[j+1][0]):
4196
+
4197
+ if not (intv_roots[j][0].upper() < intv_roots[j+1][0].lower()):
4198
+ ok = False
4199
+
4200
+ if ok:
4201
+ break
4202
+
4203
+ if retval=='interval':
4204
+ return [(r[0], r[2]) for r in intv_roots]
4205
+
4206
+ if retval=='algebraic_real':
4207
+ return [(AA.polynomial_root(r[1], r[0]), r[2]) for r in intv_roots]
4208
+
4209
+ raise ValueError("Illegal retval parameter " + retval)
4210
+
4211
+
4212
+ def scale_intvec_var(Vector_integer_dense c, k):
4213
+ """
4214
+ Given a vector of integers c of length n+1, and a rational
4215
+ k == kn / kd, multiplies each element c[i] by (kd^i)*(kn^(n-i)).
4216
+
4217
+ Modifies the input vector; has no return value.
4218
+
4219
+ EXAMPLES::
4220
+
4221
+ sage: from sage.rings.polynomial.real_roots import *
4222
+ sage: v = vector(ZZ, [1, 1, 1, 1])
4223
+ sage: scale_intvec_var(v, 3/4)
4224
+ sage: v
4225
+ (64, 48, 36, 27)
4226
+ """
4227
+
4228
+ kn = numerator(k)
4229
+ kd = denominator(k)
4230
+
4231
+ # XXX could use direct mpz calls for more speed
4232
+ cdef Integer factor = Integer(kd) ** (len(c) - 1)
4233
+
4234
+ cdef int i
4235
+ for i from 0 <= i < len(c):
4236
+ c[i] = c[i] * factor
4237
+ factor = (factor * kn) // kd
4238
+
4239
+
4240
+ def taylor_shift1_intvec(Vector_integer_dense c):
4241
+ """
4242
+ Given a vector of integers c of length d+1, representing the
4243
+ coefficients of a degree-d polynomial p, modify the vector
4244
+ to perform a Taylor shift by 1 (that is, p becomes p(x+1)).
4245
+
4246
+ This is the straightforward algorithm, which is not asymptotically
4247
+ optimal.
4248
+
4249
+ Modifies the input vector; has no return value.
4250
+
4251
+ EXAMPLES::
4252
+
4253
+ sage: from sage.rings.polynomial.real_roots import *
4254
+ sage: x = polygen(ZZ)
4255
+ sage: p = (x-1)*(x-2)*(x-3)
4256
+ sage: v = vector(ZZ, p.list())
4257
+ sage: p, v
4258
+ (x^3 - 6*x^2 + 11*x - 6, (-6, 11, -6, 1))
4259
+ sage: taylor_shift1_intvec(v)
4260
+ sage: p(x+1), v
4261
+ (x^3 - 3*x^2 + 2*x, (0, 2, -3, 1))
4262
+ """
4263
+ cdef int degree = len(c) - 1
4264
+
4265
+ cdef int i, k
4266
+ for i from 1 <= i <= degree:
4267
+ for k from degree-i <= k < degree:
4268
+ mpz_add(c._entries[k], c._entries[k], c._entries[k+1])
4269
+
4270
+
4271
+ def reverse_intvec(Vector_integer_dense c):
4272
+ """
4273
+ Given a vector of integers, reverse the vector (like the reverse()
4274
+ method on lists).
4275
+
4276
+ Modifies the input vector; has no return value.
4277
+
4278
+ EXAMPLES::
4279
+
4280
+ sage: from sage.rings.polynomial.real_roots import *
4281
+ sage: v = vector(ZZ, [1, 2, 3, 4]); v
4282
+ (1, 2, 3, 4)
4283
+ sage: reverse_intvec(v)
4284
+ sage: v
4285
+ (4, 3, 2, 1)
4286
+ """
4287
+ cdef int i
4288
+ cdef int c_len = len(c)
4289
+ for i from 0 <= i < c_len // 2:
4290
+ mpz_swap(c._entries[i], c._entries[c_len - 1 - i])
4291
+
4292
+
4293
+ realfield_rndu_cache = {}
4294
+
4295
+
4296
+ def get_realfield_rndu(n):
4297
+ """
4298
+ A simple cache for RealField fields (with rounding set to
4299
+ round-to-positive-infinity).
4300
+
4301
+ EXAMPLES::
4302
+
4303
+ sage: from sage.rings.polynomial.real_roots import *
4304
+ sage: get_realfield_rndu(20)
4305
+ Real Field with 20 bits of precision and rounding RNDU
4306
+ sage: get_realfield_rndu(53)
4307
+ Real Field with 53 bits of precision and rounding RNDU
4308
+ sage: get_realfield_rndu(20)
4309
+ Real Field with 20 bits of precision and rounding RNDU
4310
+ """
4311
+ try:
4312
+ return realfield_rndu_cache[n]
4313
+ except KeyError:
4314
+ fld = RealField(n, rnd='RNDU')
4315
+ realfield_rndu_cache[n] = fld
4316
+ return fld
4317
+
4318
+
4319
+ cdef class context:
4320
+ """
4321
+ A simple context class, which is passed through parts of the
4322
+ real root isolation algorithm to avoid global variables.
4323
+
4324
+ Holds logging information, a random number generator, and
4325
+ the target machine wordsize.
4326
+ """
4327
+
4328
+ def __init__(self, do_logging, seed, wordsize):
4329
+ """
4330
+ Initialize a context class.
4331
+ """
4332
+ self.seed = seed # saved to make context printable
4333
+ self.random = randstate().python_random(seed=seed)
4334
+ self.do_logging = do_logging
4335
+ self.wordsize = wordsize
4336
+ self.dc_log = []
4337
+ self.be_log = []
4338
+
4339
+ def __repr__(self):
4340
+ """
4341
+ Return a short summary of this context.
4342
+
4343
+ EXAMPLES::
4344
+
4345
+ sage: from sage.rings.polynomial.real_roots import *
4346
+ sage: mk_context()
4347
+ root isolation context: seed=0
4348
+ sage: mk_context(do_logging=True, seed=37, wordsize=64)
4349
+ root isolation context: seed=37; do_logging=True; wordsize=64
4350
+ """
4351
+
4352
+ s = "root isolation context: seed=%d" % self.seed
4353
+ if self.do_logging:
4354
+ s = s + "; do_logging=True"
4355
+ if self.wordsize != 32:
4356
+ s = s + "; wordsize=%d" % self.wordsize
4357
+ return s
4358
+
4359
+ cdef void dc_log_append(self, x) noexcept:
4360
+ """
4361
+ Optional logging for the root isolation algorithm.
4362
+ """
4363
+ if self.do_logging:
4364
+ self.dc_log.append(x)
4365
+
4366
+ cdef void be_log_append(self, x) noexcept:
4367
+ """
4368
+ Optional logging for degree reduction in the root isolation algorithm.
4369
+ """
4370
+ if self.do_logging:
4371
+ self.be_log.append(x)
4372
+
4373
+ def get_dc_log(self):
4374
+ return self.dc_log
4375
+
4376
+ def get_be_log(self):
4377
+ return self.be_log
4378
+
4379
+
4380
+ def mk_context(do_logging=False, seed=0, wordsize=32):
4381
+ """
4382
+ A simple wrapper for creating context objects with coercions,
4383
+ defaults, etc.
4384
+
4385
+ For use in doctests.
4386
+
4387
+ EXAMPLES::
4388
+
4389
+ sage: from sage.rings.polynomial.real_roots import *
4390
+ sage: mk_context(do_logging=True, seed=3, wordsize=64)
4391
+ root isolation context: seed=3; do_logging=True; wordsize=64
4392
+ """
4393
+ return context(do_logging, seed, wordsize)
4394
+
4395
+
4396
+ def to_bernstein(p, low=0, high=1, degree=None):
4397
+ """
4398
+ Given a polynomial p with integer coefficients, and rational
4399
+ bounds low and high, compute the exact rational Bernstein
4400
+ coefficients of p over the region [low .. high]. The optional
4401
+ parameter degree can be used to give a formal degree higher than
4402
+ the actual degree.
4403
+
4404
+ The return value is a pair (c, scale); c represents the same
4405
+ polynomial as p*scale. (If you only care about the roots of
4406
+ the polynomial, then of course scale can be ignored.)
4407
+
4408
+ EXAMPLES::
4409
+
4410
+ sage: from sage.rings.polynomial.real_roots import *
4411
+ sage: x = polygen(ZZ)
4412
+ sage: to_bernstein(x)
4413
+ ([0, 1], 1)
4414
+ sage: to_bernstein(x, degree=5)
4415
+ ([0, 1/5, 2/5, 3/5, 4/5, 1], 1)
4416
+ sage: to_bernstein(x^3 + x^2 - x - 1, low=-3, high=3)
4417
+ ([-16, 24, -32, 32], 1)
4418
+ sage: to_bernstein(x^3 + x^2 - x - 1, low=3, high=22/7)
4419
+ ([296352, 310464, 325206, 340605], 9261)
4420
+ """
4421
+ if degree is None:
4422
+ degree = p.degree()
4423
+ elif degree < p.degree():
4424
+ raise ValueError('Bernstein degree must be at least polynomial degree')
4425
+ vs = ZZ ** (degree + 1)
4426
+ c = vs(0)
4427
+ for i in range(p.degree() + 1):
4428
+ c[i] = p[i]
4429
+ scale = ZZ(1)
4430
+ if low == 0:
4431
+ scale_intvec_var(c, high)
4432
+ scale = denominator(high) ** degree
4433
+ else:
4434
+ scale_intvec_var(c, low)
4435
+ scale = denominator(low) ** degree
4436
+ taylor_shift1_intvec(c)
4437
+ scv = QQ(high - low) / low
4438
+ scale_intvec_var(c, scv)
4439
+ scale = scale * denominator(scv) ** degree
4440
+ reverse_intvec(c)
4441
+ taylor_shift1_intvec(c)
4442
+ reverse_intvec(c)
4443
+ return ([c[k] / binomial(degree, k) for k in range(degree + 1)], scale)
4444
+
4445
+
4446
+ def to_bernstein_warp(p):
4447
+ """
4448
+ Given a polynomial p with rational coefficients, compute the
4449
+ exact rational Bernstein coefficients of p(x/(x+1)).
4450
+
4451
+ EXAMPLES::
4452
+
4453
+ sage: from sage.rings.polynomial.real_roots import *
4454
+ sage: x = polygen(ZZ)
4455
+ sage: to_bernstein_warp(1 + x + x^2 + x^3 + x^4 + x^5)
4456
+ [1, 1/5, 1/10, 1/10, 1/5, 1]
4457
+ """
4458
+ c = p.list()
4459
+ for i in range(len(c)):
4460
+ c[i] = c[i] / binomial(len(c) - 1, i)
4461
+ return c
4462
+
4463
+
4464
+ def bernstein_expand(Vector_integer_dense c, int d2):
4465
+ """
4466
+ Given an integer vector representing a Bernstein polynomial p, and
4467
+ a degree d2, compute the representation of p as a Bernstein
4468
+ polynomial of formal degree d2.
4469
+
4470
+ This is similar to multiplying by the result of bernstein_up, but
4471
+ should be faster for large d2 (this has about the same number of
4472
+ multiplies, but in this version all the multiplies are by single
4473
+ machine words).
4474
+
4475
+ This returns a pair consisting of the expanded polynomial, and the maximum
4476
+ error E. (So if an element of the returned polynomial is a, and the
4477
+ true value of that coefficient is b, then a <= b < a + E.)
4478
+
4479
+ EXAMPLES::
4480
+
4481
+ sage: from sage.rings.polynomial.real_roots import *
4482
+ sage: c = vector(ZZ, [1000, 2000, -3000])
4483
+ sage: bernstein_expand(c, 3)
4484
+ ((1000, 1666, 333, -3000), 1)
4485
+ sage: bernstein_expand(c, 4)
4486
+ ((1000, 1500, 1000, -500, -3000), 1)
4487
+ sage: bernstein_expand(c, 20)
4488
+ ((1000, 1100, 1168, 1205, 1210, 1184, 1126, 1036, 915, 763, 578, 363, 115, -164, -474, -816, -1190, -1595, -2032, -2500, -3000), 1)
4489
+ """
4490
+ cdef int d1 = len(c)-1
4491
+
4492
+ vs = FreeModule(ZZ, d2+1)
4493
+
4494
+ cdef Vector_integer_dense c2 = vs(0)
4495
+
4496
+ cdef int i, j
4497
+
4498
+ cdef int ndivides = 0
4499
+
4500
+ cdef mpz_t tmp
4501
+ cdef mpz_t divisor
4502
+
4503
+ mpz_init(tmp)
4504
+ mpz_init_set_ui(divisor, 1)
4505
+
4506
+ # XXX do experimentation here on how to decide when to divide
4507
+ cdef int max_bits = max_bitsize_intvec(c) / 2
4508
+ if max_bits < 64:
4509
+ max_bits = 64
4510
+
4511
+ for i from 0 <= i <= d1:
4512
+ mpz_set(c2._entries[i], c._entries[i])
4513
+
4514
+ for i from d1 <= i < d2:
4515
+ for j from i >= j >= 0:
4516
+ mpz_addmul_ui(c2._entries[j+1], c2._entries[j], j+1)
4517
+
4518
+ mpz_mul_ui(c2._entries[j], c2._entries[j], i+1-j)
4519
+
4520
+ mpz_mul_ui(divisor, divisor, i+1)
4521
+
4522
+ if i == d2-1 or mpz_sizeinbase(divisor, 2) > max_bits:
4523
+ for j from 0 <= j <= i+1:
4524
+ mpz_fdiv_q(c2._entries[j], c2._entries[j], divisor)
4525
+ mpz_set_ui(divisor, 1)
4526
+ ndivides = ndivides + 1
4527
+
4528
+ mpz_clear(tmp)
4529
+ mpz_clear(divisor)
4530
+
4531
+ return (c2, ndivides)
4532
+
4533
+
4534
+ cdef int max_bitsize_intvec(Vector_integer_dense b) noexcept:
4535
+ """
4536
+ Given an integer vector, find the approximate log2 of the maximum
4537
+ of the absolute values of the elements.
4538
+
4539
+ EXAMPLES::
4540
+
4541
+ sage: from sage.rings.polynomial.real_roots import *
4542
+ sage: max_bitsize_intvec_doctest(vector(ZZ, [1, 2, 3, 1024]))
4543
+ 11
4544
+ """
4545
+ cdef int max_bits = 0
4546
+ cdef int i
4547
+ cdef int size
4548
+
4549
+ for i in range(len(b)):
4550
+ size = mpz_sizeinbase(b._entries[i], 2)
4551
+ if size > max_bits:
4552
+ max_bits = size
4553
+
4554
+ return max_bits
4555
+
4556
+
4557
+ def max_bitsize_intvec_doctest(b):
4558
+ return max_bitsize_intvec(b)
4559
+
4560
+
4561
+ def dprod_imatrow_vec(Matrix_integer_dense m, Vector_integer_dense v, int k):
4562
+ """
4563
+ Compute the dot product of row k of the matrix m with the vector v
4564
+ (that is, compute one element of the product m*v).
4565
+
4566
+ If v has more elements than m has columns, then elements of v are
4567
+ selected using subsample_vec.
4568
+
4569
+ EXAMPLES::
4570
+
4571
+ sage: from sage.rings.polynomial.real_roots import *
4572
+ sage: m = matrix(3, range(9))
4573
+ sage: dprod_imatrow_vec(m, vector(ZZ, [1, 0, 0, 0]), 1)
4574
+ 0
4575
+ sage: dprod_imatrow_vec(m, vector(ZZ, [0, 1, 0, 0]), 1)
4576
+ 3
4577
+ sage: dprod_imatrow_vec(m, vector(ZZ, [0, 0, 1, 0]), 1)
4578
+ 4
4579
+ sage: dprod_imatrow_vec(m, vector(ZZ, [0, 0, 0, 1]), 1)
4580
+ 5
4581
+ sage: dprod_imatrow_vec(m, vector(ZZ, [1, 0, 0]), 1)
4582
+ 3
4583
+ sage: dprod_imatrow_vec(m, vector(ZZ, [0, 1, 0]), 1)
4584
+ 4
4585
+ sage: dprod_imatrow_vec(m, vector(ZZ, [0, 0, 1]), 1)
4586
+ 5
4587
+ sage: dprod_imatrow_vec(m, vector(ZZ, [1, 2, 3]), 1)
4588
+ 26
4589
+ """
4590
+ assert 0 <= k < m.nrows()
4591
+ assert m.ncols() <= len(v)
4592
+
4593
+ cdef Integer sum = Integer(0)
4594
+
4595
+ cdef mpz_t tmp
4596
+
4597
+ cdef int msize = m.ncols()
4598
+ cdef int vsize = len(v)
4599
+ cdef int ra
4600
+ cdef int a
4601
+ mpz_init(tmp)
4602
+ for a in range(msize):
4603
+ ra = subsample_vec(a, msize, vsize)
4604
+ m.get_unsafe_mpz(k, a, tmp)
4605
+ mpz_addmul(sum.value, tmp, v._entries[ra])
4606
+ mpz_clear(tmp)
4607
+ return sum
4608
+
4609
+
4610
+ def min_max_delta_intvec(Vector_integer_dense a, Vector_integer_dense b):
4611
+ """
4612
+ Given two integer vectors a and b (of equal, nonzero length), return
4613
+ a pair of the minimum and maximum values taken on by a[i] - b[i].
4614
+
4615
+ EXAMPLES::
4616
+
4617
+ sage: from sage.rings.polynomial.real_roots import *
4618
+ sage: a = vector(ZZ, [10, -30])
4619
+ sage: b = vector(ZZ, [15, -60])
4620
+ sage: min_max_delta_intvec(a, b)
4621
+ (30, -5)
4622
+ """
4623
+ assert len(a) == len(b)
4624
+ assert len(a) > 0
4625
+
4626
+ cdef Integer max = Integer()
4627
+ cdef Integer min = Integer()
4628
+
4629
+ cdef mpz_t tmp
4630
+ mpz_init(tmp)
4631
+
4632
+ cdef int i
4633
+ for i from 0 <= i < len(a):
4634
+ mpz_sub(tmp, a._entries[i], b._entries[i])
4635
+ if i == 0 or mpz_cmp(tmp, max.value) > 0:
4636
+ mpz_set(max.value, tmp)
4637
+ if i == 0 or mpz_cmp(tmp, min.value) < 0:
4638
+ mpz_set(min.value, tmp)
4639
+
4640
+ mpz_clear(tmp)
4641
+
4642
+ return (max, min)
4643
+
4644
+
4645
+ def min_max_diff_intvec(Vector_integer_dense b):
4646
+ """
4647
+ Given an integer vector b = (b0, ..., bn), compute the
4648
+ minimum and maximum values of b_{j+1} - b_j.
4649
+
4650
+ EXAMPLES::
4651
+
4652
+ sage: from sage.rings.polynomial.real_roots import *
4653
+ sage: min_max_diff_intvec(vector(ZZ, [1, 7, -2]))
4654
+ (-9, 6)
4655
+ """
4656
+ l = len(b)
4657
+ assert l > 1
4658
+
4659
+ cdef Integer min_diff = b[1] - b[0]
4660
+ cdef Integer max_diff = Integer()
4661
+
4662
+ cdef Integer diff = Integer()
4663
+
4664
+ mpz_set(max_diff.value, min_diff.value)
4665
+
4666
+ for i from 1 <= i < l-1:
4667
+ mpz_sub(diff.value, b._entries[i+1], b._entries[i])
4668
+ if mpz_cmp(diff.value, max_diff.value) > 0:
4669
+ mpz_set(max_diff.value, diff.value)
4670
+ if mpz_cmp(diff.value, min_diff.value) < 0:
4671
+ mpz_set(min_diff.value, diff.value)
4672
+
4673
+ return (min_diff, max_diff)
4674
+
4675
+
4676
+ def min_max_diff_doublevec(Vector_real_double_dense c):
4677
+ """
4678
+ Given a floating-point vector b = (b0, ..., bn), compute the
4679
+ minimum and maximum values of b_{j+1} - b_j.
4680
+
4681
+ EXAMPLES::
4682
+
4683
+ sage: from sage.rings.polynomial.real_roots import *
4684
+ sage: min_max_diff_doublevec(vector(RDF, [1, 7, -2]))
4685
+ (-9.0, 6.0)
4686
+ """
4687
+ cdef numpy.ndarray[double, ndim=1] cd = c._vector_numpy
4688
+
4689
+ l = len(c)
4690
+ assert l > 1
4691
+
4692
+ cdef double min_diff = cd[1] - cd[0]
4693
+ cdef double max_diff = min_diff
4694
+
4695
+ cdef double diff
4696
+
4697
+ for i from 1 <= i < l-1:
4698
+ diff = cd[i+1] - cd[i]
4699
+ if diff < min_diff:
4700
+ min_diff = diff
4701
+ if diff > max_diff:
4702
+ max_diff = diff
4703
+
4704
+ return (min_diff, max_diff)