passagemath-symbolics 10.8.1a1__cp311-cp311-macosx_13_0_arm64.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 (182) hide show
  1. passagemath_symbolics/.dylibs/libgmp.10.dylib +0 -0
  2. passagemath_symbolics/__init__.py +3 -0
  3. passagemath_symbolics-10.8.1a1.dist-info/METADATA +186 -0
  4. passagemath_symbolics-10.8.1a1.dist-info/RECORD +182 -0
  5. passagemath_symbolics-10.8.1a1.dist-info/WHEEL +6 -0
  6. passagemath_symbolics-10.8.1a1.dist-info/top_level.txt +3 -0
  7. sage/all__sagemath_symbolics.py +17 -0
  8. sage/calculus/all.py +14 -0
  9. sage/calculus/calculus.py +2838 -0
  10. sage/calculus/desolvers.py +1864 -0
  11. sage/calculus/predefined.py +51 -0
  12. sage/calculus/tests.py +225 -0
  13. sage/calculus/var.cpython-311-darwin.so +0 -0
  14. sage/calculus/var.pyx +401 -0
  15. sage/dynamics/all__sagemath_symbolics.py +6 -0
  16. sage/dynamics/complex_dynamics/all.py +5 -0
  17. sage/dynamics/complex_dynamics/mandel_julia.py +765 -0
  18. sage/dynamics/complex_dynamics/mandel_julia_helper.cpython-311-darwin.so +0 -0
  19. sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +1034 -0
  20. sage/ext/all__sagemath_symbolics.py +1 -0
  21. sage/ext_data/kenzo/CP2.txt +45 -0
  22. sage/ext_data/kenzo/CP3.txt +349 -0
  23. sage/ext_data/kenzo/CP4.txt +4774 -0
  24. sage/ext_data/kenzo/README.txt +49 -0
  25. sage/ext_data/kenzo/S4.txt +20 -0
  26. sage/ext_data/magma/latex/latex.m +1021 -0
  27. sage/ext_data/magma/latex/latex.spec +1 -0
  28. sage/ext_data/magma/sage/basic.m +356 -0
  29. sage/ext_data/magma/sage/sage.spec +1 -0
  30. sage/ext_data/magma/spec +9 -0
  31. sage/geometry/all__sagemath_symbolics.py +8 -0
  32. sage/geometry/hyperbolic_space/all.py +5 -0
  33. sage/geometry/hyperbolic_space/hyperbolic_coercion.py +755 -0
  34. sage/geometry/hyperbolic_space/hyperbolic_constants.py +5 -0
  35. sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +2419 -0
  36. sage/geometry/hyperbolic_space/hyperbolic_interface.py +206 -0
  37. sage/geometry/hyperbolic_space/hyperbolic_isometry.py +1083 -0
  38. sage/geometry/hyperbolic_space/hyperbolic_model.py +1502 -0
  39. sage/geometry/hyperbolic_space/hyperbolic_point.py +621 -0
  40. sage/geometry/riemannian_manifolds/all.py +7 -0
  41. sage/geometry/riemannian_manifolds/parametrized_surface3d.py +1632 -0
  42. sage/geometry/riemannian_manifolds/surface3d_generators.py +461 -0
  43. sage/interfaces/all__sagemath_symbolics.py +1 -0
  44. sage/interfaces/magma.py +2991 -0
  45. sage/interfaces/magma_free.py +90 -0
  46. sage/interfaces/maple.py +1402 -0
  47. sage/interfaces/mathematica.py +1345 -0
  48. sage/interfaces/mathics.py +1312 -0
  49. sage/interfaces/sympy.py +1398 -0
  50. sage/interfaces/sympy_wrapper.py +197 -0
  51. sage/interfaces/tides.py +938 -0
  52. sage/libs/all__sagemath_symbolics.py +6 -0
  53. sage/manifolds/all.py +7 -0
  54. sage/manifolds/calculus_method.py +553 -0
  55. sage/manifolds/catalog.py +437 -0
  56. sage/manifolds/chart.py +4010 -0
  57. sage/manifolds/chart_func.py +3416 -0
  58. sage/manifolds/continuous_map.py +2183 -0
  59. sage/manifolds/continuous_map_image.py +155 -0
  60. sage/manifolds/differentiable/affine_connection.py +2475 -0
  61. sage/manifolds/differentiable/all.py +1 -0
  62. sage/manifolds/differentiable/automorphismfield.py +1383 -0
  63. sage/manifolds/differentiable/automorphismfield_group.py +604 -0
  64. sage/manifolds/differentiable/bundle_connection.py +1445 -0
  65. sage/manifolds/differentiable/characteristic_cohomology_class.py +1840 -0
  66. sage/manifolds/differentiable/chart.py +1241 -0
  67. sage/manifolds/differentiable/curve.py +1028 -0
  68. sage/manifolds/differentiable/de_rham_cohomology.py +541 -0
  69. sage/manifolds/differentiable/degenerate.py +559 -0
  70. sage/manifolds/differentiable/degenerate_submanifold.py +1668 -0
  71. sage/manifolds/differentiable/diff_form.py +1660 -0
  72. sage/manifolds/differentiable/diff_form_module.py +1062 -0
  73. sage/manifolds/differentiable/diff_map.py +1315 -0
  74. sage/manifolds/differentiable/differentiable_submanifold.py +291 -0
  75. sage/manifolds/differentiable/examples/all.py +1 -0
  76. sage/manifolds/differentiable/examples/euclidean.py +2517 -0
  77. sage/manifolds/differentiable/examples/real_line.py +897 -0
  78. sage/manifolds/differentiable/examples/sphere.py +1186 -0
  79. sage/manifolds/differentiable/examples/symplectic_space.py +187 -0
  80. sage/manifolds/differentiable/examples/symplectic_space_test.py +40 -0
  81. sage/manifolds/differentiable/integrated_curve.py +4035 -0
  82. sage/manifolds/differentiable/levi_civita_connection.py +841 -0
  83. sage/manifolds/differentiable/manifold.py +4254 -0
  84. sage/manifolds/differentiable/manifold_homset.py +1826 -0
  85. sage/manifolds/differentiable/metric.py +3032 -0
  86. sage/manifolds/differentiable/mixed_form.py +1507 -0
  87. sage/manifolds/differentiable/mixed_form_algebra.py +559 -0
  88. sage/manifolds/differentiable/multivector_module.py +800 -0
  89. sage/manifolds/differentiable/multivectorfield.py +1522 -0
  90. sage/manifolds/differentiable/poisson_tensor.py +268 -0
  91. sage/manifolds/differentiable/pseudo_riemannian.py +755 -0
  92. sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +1839 -0
  93. sage/manifolds/differentiable/scalarfield.py +1343 -0
  94. sage/manifolds/differentiable/scalarfield_algebra.py +472 -0
  95. sage/manifolds/differentiable/symplectic_form.py +912 -0
  96. sage/manifolds/differentiable/symplectic_form_test.py +220 -0
  97. sage/manifolds/differentiable/tangent_space.py +412 -0
  98. sage/manifolds/differentiable/tangent_vector.py +616 -0
  99. sage/manifolds/differentiable/tensorfield.py +4665 -0
  100. sage/manifolds/differentiable/tensorfield_module.py +963 -0
  101. sage/manifolds/differentiable/tensorfield_paral.py +2450 -0
  102. sage/manifolds/differentiable/tensorfield_paral_test.py +16 -0
  103. sage/manifolds/differentiable/vector_bundle.py +1725 -0
  104. sage/manifolds/differentiable/vectorfield.py +1717 -0
  105. sage/manifolds/differentiable/vectorfield_module.py +2445 -0
  106. sage/manifolds/differentiable/vectorframe.py +1832 -0
  107. sage/manifolds/family.py +270 -0
  108. sage/manifolds/local_frame.py +1490 -0
  109. sage/manifolds/manifold.py +3090 -0
  110. sage/manifolds/manifold_homset.py +452 -0
  111. sage/manifolds/operators.py +359 -0
  112. sage/manifolds/point.py +994 -0
  113. sage/manifolds/scalarfield.py +3718 -0
  114. sage/manifolds/scalarfield_algebra.py +629 -0
  115. sage/manifolds/section.py +3111 -0
  116. sage/manifolds/section_module.py +831 -0
  117. sage/manifolds/structure.py +229 -0
  118. sage/manifolds/subset.py +2721 -0
  119. sage/manifolds/subsets/all.py +1 -0
  120. sage/manifolds/subsets/closure.py +131 -0
  121. sage/manifolds/subsets/pullback.py +883 -0
  122. sage/manifolds/topological_submanifold.py +891 -0
  123. sage/manifolds/trivialization.py +733 -0
  124. sage/manifolds/utilities.py +1348 -0
  125. sage/manifolds/vector_bundle.py +1347 -0
  126. sage/manifolds/vector_bundle_fiber.py +332 -0
  127. sage/manifolds/vector_bundle_fiber_element.py +111 -0
  128. sage/matrix/all__sagemath_symbolics.py +1 -0
  129. sage/matrix/matrix_symbolic_dense.cpython-311-darwin.so +0 -0
  130. sage/matrix/matrix_symbolic_dense.pxd +6 -0
  131. sage/matrix/matrix_symbolic_dense.pyx +1030 -0
  132. sage/matrix/matrix_symbolic_sparse.cpython-311-darwin.so +0 -0
  133. sage/matrix/matrix_symbolic_sparse.pxd +6 -0
  134. sage/matrix/matrix_symbolic_sparse.pyx +1038 -0
  135. sage/modules/all__sagemath_symbolics.py +1 -0
  136. sage/modules/vector_callable_symbolic_dense.py +105 -0
  137. sage/modules/vector_symbolic_dense.py +116 -0
  138. sage/modules/vector_symbolic_sparse.py +118 -0
  139. sage/rings/all__sagemath_symbolics.py +4 -0
  140. sage/rings/asymptotic/all.py +6 -0
  141. sage/rings/asymptotic/asymptotic_expansion_generators.py +1485 -0
  142. sage/rings/asymptotic/asymptotic_ring.py +4858 -0
  143. sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +4106 -0
  144. sage/rings/asymptotic/growth_group.py +5373 -0
  145. sage/rings/asymptotic/growth_group_cartesian.py +1400 -0
  146. sage/rings/asymptotic/term_monoid.py +5205 -0
  147. sage/rings/function_field/all__sagemath_symbolics.py +2 -0
  148. sage/rings/polynomial/all__sagemath_symbolics.py +1 -0
  149. sage/symbolic/all.py +15 -0
  150. sage/symbolic/assumptions.py +987 -0
  151. sage/symbolic/benchmark.py +93 -0
  152. sage/symbolic/callable.py +456 -0
  153. sage/symbolic/callable.pyi +66 -0
  154. sage/symbolic/comparison_impl.pyi +38 -0
  155. sage/symbolic/complexity_measures.py +35 -0
  156. sage/symbolic/constants.py +1286 -0
  157. sage/symbolic/constants_c_impl.pyi +10 -0
  158. sage/symbolic/expression_conversion_algebraic.py +310 -0
  159. sage/symbolic/expression_conversion_sympy.py +317 -0
  160. sage/symbolic/expression_conversions.py +1727 -0
  161. sage/symbolic/function_factory.py +355 -0
  162. sage/symbolic/function_factory.pyi +41 -0
  163. sage/symbolic/getitem_impl.pyi +24 -0
  164. sage/symbolic/integration/all.py +1 -0
  165. sage/symbolic/integration/external.py +271 -0
  166. sage/symbolic/integration/integral.py +1075 -0
  167. sage/symbolic/maxima_wrapper.py +162 -0
  168. sage/symbolic/operators.py +267 -0
  169. sage/symbolic/operators.pyi +61 -0
  170. sage/symbolic/pynac_constant_impl.pyi +13 -0
  171. sage/symbolic/pynac_function_impl.pyi +8 -0
  172. sage/symbolic/random_tests.py +461 -0
  173. sage/symbolic/relation.py +2062 -0
  174. sage/symbolic/ring.cpython-311-darwin.so +0 -0
  175. sage/symbolic/ring.pxd +5 -0
  176. sage/symbolic/ring.pyi +110 -0
  177. sage/symbolic/ring.pyx +1393 -0
  178. sage/symbolic/series_impl.pyi +10 -0
  179. sage/symbolic/subring.py +1025 -0
  180. sage/symbolic/symengine.py +19 -0
  181. sage/symbolic/tests.py +40 -0
  182. sage/symbolic/units.py +1468 -0
@@ -0,0 +1,2991 @@
1
+ # sage_setup: distribution = sagemath-symbolics
2
+ r"""
3
+ Interface to Magma
4
+
5
+ Sage provides an interface to the Magma computational algebra
6
+ system. This system provides extensive functionality for number
7
+ theory, group theory, combinatorics and algebra.
8
+
9
+ .. NOTE::
10
+
11
+ You must have Magma installed on your
12
+ computer for this interface to work. Magma is not free, so it is
13
+ not included with Sage, but you can obtain it from
14
+ https://magma.maths.usyd.edu.au/.
15
+
16
+ The Magma interface offers three pieces of functionality:
17
+
18
+ #. ``magma_console()`` -- a function that dumps you into an interactive command-line Magma session.
19
+
20
+ #. ``magma.new(obj)`` and alternatively ``magma(obj)`` -- creation of a Magma object from a Sage object ``obj``.
21
+ This provides a Pythonic interface to Magma. For example, if ``f=magma.new(10)``, then
22
+ ``f.Factors()`` returns the prime factorization of 10 computed using Magma. If obj is a string containing
23
+ an arbitrary Magma expression, then the expression is evaluated in Magma to create a Magma object. An example
24
+ is ``magma.new('10 div 3')``, which returns Magma integer 3.
25
+
26
+ #. ``magma.eval(expr)`` -- evaluation of the Magma expression ``expr``, with the result returned as a string.
27
+
28
+ Type ``magma.[tab]`` for a list of all functions available from your Magma.
29
+ Type ``magma.Function?`` for Magma's help about the Magma ``Function``.
30
+
31
+ Parameters
32
+ ----------
33
+
34
+ Some Magma functions have optional "parameters", which are
35
+ arguments that in Magma go after a colon. In Sage, you pass these
36
+ using named function arguments. For example,
37
+
38
+ ::
39
+
40
+ sage: E = magma('EllipticCurve([0,1,1,-1,0])') # optional - magma
41
+ sage: E.Rank(Bound = 5) # optional - magma
42
+ 0
43
+
44
+ Multiple Return Values
45
+ ----------------------
46
+
47
+ Some Magma functions return more than one value. You can control
48
+ how many you get using the ``nvals`` named parameter to
49
+ a function call::
50
+
51
+ sage: # optional - magma
52
+ sage: n = magma(100)
53
+ sage: n.IsSquare(nvals = 1)
54
+ true
55
+ sage: n.IsSquare(nvals = 2)
56
+ (true, 10)
57
+ sage: n = magma(-2006)
58
+ sage: n.Factorization()
59
+ [ <2, 1>, <17, 1>, <59, 1> ]
60
+ sage: n.Factorization(nvals=2)
61
+ ([ <2, 1>, <17, 1>, <59, 1> ], -1)
62
+
63
+ We verify that an obviously principal ideal is principal::
64
+
65
+ sage: # optional - magma
66
+ sage: _ = magma.eval('R<x> := PolynomialRing(RationalField())')
67
+ sage: O = magma.NumberField('x^2+23').MaximalOrder()
68
+ sage: I = magma('ideal<%s|%s.1>'%(O.name(),O.name()))
69
+ sage: I.IsPrincipal(nvals=2)
70
+ (true, [1, 0])
71
+
72
+ Long Input
73
+ ----------
74
+
75
+ The Magma interface reads in even very long input (using files) in
76
+ a robust manner.
77
+
78
+ ::
79
+
80
+ sage: t = '"%s"'%10^10000 # ten thousand character string. # optional - magma
81
+ sage: a = magma.eval(t) # optional - magma
82
+ sage: a = magma(t) # optional - magma
83
+
84
+ Garbage Collection
85
+ ------------------
86
+
87
+ There is a subtle point with the Magma interface, which arises from
88
+ how garbage collection works. Consider the following session:
89
+
90
+ First, create a matrix m in Sage::
91
+
92
+ sage: m=matrix(ZZ,2,[1,2,3,4]) # optional - magma
93
+
94
+ Then I create a corresponding matrix A in Magma::
95
+
96
+ sage: A = magma(m) # optional - magma
97
+
98
+ It is called _sage_[...] in Magma::
99
+
100
+ sage: s = A.name(); s # optional - magma
101
+ '_sage_[...]'
102
+
103
+ It's there::
104
+
105
+ sage: magma.eval(s) # optional - magma
106
+ '[1 2]\n[3 4]'
107
+
108
+ Now I delete the reference to that matrix::
109
+
110
+ sage: del A # optional - magma
111
+
112
+ Now _sage_[...] is "zeroed out" in the Magma session::
113
+
114
+ sage: magma.eval(s) # optional - magma
115
+ '0'
116
+
117
+ If Sage did not do this garbage collection, then every single time you
118
+ ever create any magma object from a sage object, e.g., by doing
119
+ magma(m), you would use up a lot of memory in that Magma session.
120
+ This would lead to a horrible memory leak situation, which would make
121
+ the Magma interface nearly useless for serious work.
122
+
123
+
124
+ Other Examples
125
+ --------------
126
+
127
+ We compute a space of modular forms with character.
128
+
129
+ ::
130
+
131
+ sage: N = 20
132
+ sage: D = 20
133
+ sage: eps_top = fundamental_discriminant(D)
134
+ sage: eps = magma.KroneckerCharacter(eps_top, RationalField()) # optional - magma
135
+ sage: M2 = magma.ModularForms(eps) # optional - magma
136
+ sage: print(M2) # optional - magma
137
+ Space of modular forms on Gamma_1(5) ...
138
+ sage: print(M2.Basis()) # optional - magma
139
+ [
140
+ 1 + 10*q^2 + 20*q^3 + 20*q^5 + 60*q^7 + ...
141
+ q + q^2 + 2*q^3 + 3*q^4 + 5*q^5 + 2*q^6 + ...
142
+ ]
143
+
144
+ In Sage/Python (and sort of C++) coercion of an element x into a
145
+ structure S is denoted by S(x). This also works for the Magma
146
+ interface::
147
+
148
+ sage: # optional - magma
149
+ sage: G = magma.DirichletGroup(20)
150
+ sage: G.AssignNames(['a', 'b'])
151
+ sage: (G.1).Modulus()
152
+ 20
153
+ sage: e = magma.DirichletGroup(40)(G.1)
154
+ sage: print(e)
155
+ Kronecker character -4 in modulus 40
156
+ sage: print(e.Modulus())
157
+ 40
158
+
159
+ We coerce some polynomial rings into Magma::
160
+
161
+ sage: R.<y> = PolynomialRing(QQ)
162
+ sage: S = magma(R) # optional - magma
163
+ sage: print(S) # optional - magma
164
+ Univariate Polynomial Ring in y over Rational Field
165
+ sage: S.1 # optional - magma
166
+ y
167
+
168
+ This example illustrates that Sage doesn't magically extend how
169
+ Magma implicit coercion (what there is, at least) works. The errors
170
+ below are the result of Magma having a rather limited automatic
171
+ coercion system compared to Sage's::
172
+
173
+ sage: R.<x> = ZZ[]
174
+ sage: x * 5
175
+ 5*x
176
+ sage: x * 1.0
177
+ x
178
+ sage: x * (2/3)
179
+ 2/3*x
180
+ sage: y = magma(x) # optional - magma
181
+ sage: y * 5 # optional - magma
182
+ 5*x
183
+ sage: y * 1.0 # optional - magma
184
+ $.1
185
+ sage: y * (2/3) # optional - magma
186
+ Traceback (most recent call last):
187
+ ...
188
+ TypeError: Error evaluating Magma code.
189
+ ...
190
+ Argument types given: RngUPolElt[RngInt], FldRatElt
191
+
192
+
193
+ AUTHORS:
194
+
195
+ - William Stein (2005): initial version
196
+
197
+ - William Stein (2006-02-28): added extensive tab completion and
198
+ interactive IPython documentation support.
199
+
200
+ - William Stein (2006-03-09): added nvals argument for
201
+ magma.functions...
202
+ """
203
+
204
+ # ****************************************************************************
205
+ # Copyright (C) 2005 William Stein <wstein@gmail.com>
206
+ #
207
+ # Distributed under the terms of the GNU General Public License (GPL)
208
+ #
209
+ # This code is distributed in the hope that it will be useful,
210
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
211
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
212
+ # General Public License for more details.
213
+ #
214
+ # The full text of the GPL is available at:
215
+ #
216
+ # https://www.gnu.org/licenses/
217
+ # ****************************************************************************
218
+ from pathlib import Path
219
+ import re
220
+ import sys
221
+ import os
222
+
223
+ from sage.structure.parent import Parent
224
+ from .expect import Expect, ExpectElement, ExpectFunction, FunctionElement
225
+ from sage.env import SAGE_EXTCODE, DOT_SAGE
226
+ import sage.misc.misc
227
+ import sage.misc.sage_eval
228
+ import sage.interfaces.abc
229
+ from sage.interfaces.tab_completion import ExtraTabCompletion
230
+ from sage.misc.instancedoc import instancedoc
231
+
232
+ PROMPT = ">>>"
233
+
234
+ SAGE_REF = "_sage_ref"
235
+ SAGE_REF_RE = re.compile(r'%s\d+' % SAGE_REF)
236
+
237
+ INTRINSIC_CACHE = '%s/magma_intrinsic_cache.sobj' % DOT_SAGE
238
+ EXTCODE_DIR = None
239
+
240
+
241
+ def extcode_dir(iface=None) -> str:
242
+ """
243
+ Return directory that contains all the Magma extcode.
244
+
245
+ This is put in a writable directory owned by the user, since when
246
+ attached, Magma has to write sig and lck files.
247
+
248
+ EXAMPLES::
249
+
250
+ sage: from sage.interfaces.magma import extcode_dir
251
+ sage: extcode_dir()
252
+ '...dir_.../data/'
253
+ """
254
+ global EXTCODE_DIR
255
+ if not EXTCODE_DIR:
256
+ if iface is None or iface._server is None:
257
+ import shutil
258
+ tmp = sage.misc.temporary_file.tmp_dir()
259
+ shutil.copytree('%s/magma/' % SAGE_EXTCODE, tmp + '/data')
260
+ EXTCODE_DIR = "%s/data/" % tmp
261
+ else:
262
+ tmp = iface._remote_tmpdir()
263
+ command = 'scp -q -r "%s/magma/" "%s:%s/data" 1>&2 2>/dev/null' % (SAGE_EXTCODE, iface._server, tmp)
264
+ try:
265
+ ans = os.system(command)
266
+ EXTCODE_DIR = "%s/data/" % tmp
267
+ if ans != 0:
268
+ raise OSError
269
+ except OSError:
270
+ out_str = 'Tried to copy the file structure in "%s/magma/" to "%s:%s/data" and failed (possibly because scp is not installed in the system).\nFor the remote Magma to work you should populate the remote directory by some other method, or install scp in the system and retry.' % (SAGE_EXTCODE, iface._server, tmp)
271
+ from warnings import warn
272
+ warn(out_str)
273
+ return EXTCODE_DIR
274
+
275
+
276
+ class Magma(ExtraTabCompletion, Expect):
277
+ r"""
278
+ Interface to the Magma interpreter.
279
+
280
+ Type ``magma.[tab]`` for a list of all the functions
281
+ available from your Magma install. Type
282
+ ``magma.Function?`` for Magma's help about a given ``Function``
283
+ Type ``magma(...)`` to create a new Magma
284
+ object, and ``magma.eval(...)`` to run a string using
285
+ Magma (and get the result back as a string).
286
+
287
+ .. NOTE::
288
+
289
+ If you do not own a local copy of Magma, try using the
290
+ ``magma_free`` command instead, which uses the free demo web
291
+ interface to Magma.
292
+
293
+ If you have ssh access to a remote installation of Magma, you can
294
+ also set the ``server`` parameter to use it.
295
+
296
+ EXAMPLES:
297
+
298
+ You must use nvals = 0 to call a function that doesn't return
299
+ anything, otherwise you'll get an error. (nvals is the number of
300
+ return values.)
301
+
302
+ ::
303
+
304
+ sage: magma.SetDefaultRealFieldPrecision(200, nvals=0) # magma >= v2.12; optional - magma
305
+ sage: magma.eval('1.1') # optional - magma
306
+ '1.1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
307
+ sage: magma.SetDefaultRealFieldPrecision(30, nvals=0) # optional - magma
308
+ """
309
+ def __init__(self, script_subdirectory=None,
310
+ logfile=None, server=None, server_tmpdir=None,
311
+ user_config=False, seed=None, command=None):
312
+ """
313
+ INPUT:
314
+
315
+ - ``script_subdirectory`` -- directory where scripts
316
+ are read from
317
+
318
+ - ``logfile`` -- output logged to this file
319
+
320
+ - ``server`` -- address of remote server
321
+
322
+ - ``server_tmpdir`` -- temporary directory to use in remote server
323
+
324
+ - ``user_config`` -- if ``True``, then local user
325
+ configuration files will be read by Magma. If ``False`` (the default),
326
+ then Magma is started with the -n option which suppresses user
327
+ configuration files.
328
+
329
+ - ``seed`` -- seed to use in the random number generator
330
+
331
+ - ``command`` -- (default: ``'magma'``) the command to execute to start Magma
332
+
333
+ EXAMPLES::
334
+
335
+ sage: Magma(logfile=tmp_filename())
336
+ Magma
337
+ """
338
+ if command is None:
339
+ command = os.getenv('SAGE_MAGMA_COMMAND') or 'magma'
340
+
341
+ if not user_config:
342
+ command += ' -n'
343
+
344
+ # Obtain the parameters from the environment, to allow the magma = Magma() phrase
345
+ # to work with non-default parameters.
346
+ if seed is None:
347
+ seed = os.getenv('SAGE_MAGMA_SEED')
348
+
349
+ Expect.__init__(self,
350
+ name='magma',
351
+ prompt='>>SAGE>>',
352
+ command=command,
353
+ server=server,
354
+ server_tmpdir=server_tmpdir,
355
+ script_subdirectory=script_subdirectory,
356
+ restart_on_ctrlc=False,
357
+ logfile=logfile,
358
+ eval_using_file_cutoff=100)
359
+ # We use "-n" above in the Magma startup command so
360
+ # local user startup configuration is not read.
361
+
362
+ self.__seq = 0
363
+ self.__ref = 0
364
+ self.__available_var = []
365
+ self.__cache = {}
366
+ self._preparse_colon_equals = False # if set to True, all "=" become ":=" (some users really appreciate this)
367
+ self._seed = seed
368
+
369
+ def set_seed(self, seed=None):
370
+ """
371
+ Set the seed for the Magma interpreter.
372
+
373
+ The seed should be an integer.
374
+
375
+ EXAMPLES::
376
+
377
+ sage: m = Magma() # optional - magma
378
+ sage: m.set_seed(1) # optional - magma
379
+ 1
380
+ sage: [m.Random(100) for i in range(5)] # optional - magma
381
+ [14, 81, 45, 75, 67]
382
+ """
383
+ if seed is None:
384
+ seed = self.rand_seed()
385
+ self.eval('SetSeed(%d)' % seed)
386
+ self._seed = seed
387
+ return seed
388
+
389
+ def __reduce__(self):
390
+ """
391
+ Used to pickle a magma interface instance.
392
+
393
+ Unpickling results in the default magma interpreter; this is a
394
+ choice, and perhaps not the most logical one! It means that if you
395
+ make two distinct magma interfaces, pickle both, then unpickle
396
+ them, you get back exactly the same one. We illustrate this
397
+ behavior below.
398
+
399
+ OUTPUT: function, empty tuple
400
+
401
+ EXAMPLES::
402
+
403
+ sage: from sage.interfaces.magma import magma
404
+ sage: loads(dumps(magma)) is magma
405
+ True
406
+
407
+ Unpickling always gives the default global magma interpreter::
408
+
409
+ sage: m1 = Magma(); m2 = Magma()
410
+ sage: m1 is m2
411
+ False
412
+ sage: loads(dumps(m1)) is loads(dumps(m2))
413
+ True
414
+ sage: loads(dumps(m1)) is magma
415
+ True
416
+ """
417
+ return reduce_load_Magma, tuple([])
418
+
419
+ def _read_in_file_command(self, filename) -> str:
420
+ """
421
+ Return the command in Magma that reads in the contents of the given
422
+ file.
423
+
424
+ INPUT:
425
+
426
+ - ``filename`` -- string
427
+
428
+ OUTPUT:
429
+
430
+ - ``string`` -- a magma command
431
+
432
+ EXAMPLES::
433
+
434
+ sage: magma._read_in_file_command('file.m')
435
+ 'load "file.m";'
436
+ """
437
+ return 'load "%s";' % filename
438
+
439
+ def _post_process_from_file(self, s) -> str:
440
+ r"""
441
+ Used internally in the Magma interface to post-process the result
442
+ of evaluating a string using a file. For Magma what this does is
443
+ delete the first output line, since that is a verbose output line
444
+ that Magma displays about loading a file.
445
+
446
+ INPUT:
447
+
448
+ - ``s`` -- string
449
+
450
+ OUTPUT: string
451
+
452
+ EXAMPLES::
453
+
454
+ sage: magma._post_process_from_file("Loading ...\nHello")
455
+ 'Hello'
456
+ sage: magma._post_process_from_file("Hello")
457
+ ''
458
+ """
459
+ if not isinstance(s, str):
460
+ raise RuntimeError("Error evaluating object in %s:\n%s" % (self, s))
461
+ # Chop off the annoying "Loading ... " message that Magma
462
+ # always outputs no matter what.
463
+ i = s.find('\n')
464
+ if i == -1: # special case -- command produced no output, so no \n
465
+ return ''
466
+ return s[i + 1:]
467
+
468
+ def __getattr__(self, attrname):
469
+ """
470
+ Return a formal wrapper around a Magma function, or raise an
471
+ :exc:`AttributeError` if attrname starts with an underscore.
472
+
473
+ INPUT:
474
+
475
+ - ``attrname`` -- string
476
+
477
+ OUTPUT: :class:`MagmaFunction` instance
478
+
479
+ EXAMPLES::
480
+
481
+ sage: g = magma.__getattr__('EllipticCurve')
482
+ sage: g
483
+ EllipticCurve
484
+ sage: type(g)
485
+ <class 'sage.interfaces.magma.MagmaFunction'>
486
+
487
+ In fact, __getattr__ is called implicitly in the following
488
+ case::
489
+
490
+ sage: f = magma.EllipticCurve
491
+ sage: type(f)
492
+ <class 'sage.interfaces.magma.MagmaFunction'>
493
+ sage: f
494
+ EllipticCurve
495
+ """
496
+ if attrname[:1] == "_":
497
+ raise AttributeError
498
+ return MagmaFunction(self, attrname)
499
+
500
+ def eval(self, x, strip=True, **kwds) -> str:
501
+ """
502
+ Evaluate the given block x of code in Magma and return the output
503
+ as a string.
504
+
505
+ INPUT:
506
+
507
+ - ``x`` -- string of code
508
+
509
+ - ``strip`` -- ignored
510
+
511
+ OUTPUT: string
512
+
513
+ EXAMPLES:
514
+
515
+ We evaluate a string that involves assigning to a
516
+ variable and printing.
517
+
518
+ ::
519
+
520
+ sage: magma.eval("a := 10;print 2+a;") # optional - magma
521
+ '12'
522
+
523
+ We evaluate a large input line (note that no weird output appears
524
+ and that this works quickly).
525
+
526
+ ::
527
+
528
+ sage: magma.eval("a := %s;"%(10^10000)) # optional - magma
529
+ ''
530
+
531
+ Verify that :issue:`9705` is fixed::
532
+
533
+ sage: nl=chr(10) # newline character
534
+ sage: magma.eval( # optional - magma
535
+ ....: "_<x>:=PolynomialRing(Rationals());"+nl+
536
+ ....: "repeat"+nl+
537
+ ....: " g:=3*b*x^4+18*c*x^3-6*b^2*x^2-6*b*c*x-b^3-9*c^2 where b:=Random([-10..10]) where c:=Random([-10..10]);"+nl+
538
+ ....: "until g ne 0 and Roots(g) ne [];"+nl+
539
+ ....: "print \"success\";")
540
+ 'success'
541
+
542
+ Verify that :issue:`11401` is fixed::
543
+
544
+ sage: nl=chr(10) # newline character
545
+ sage: magma.eval("a:=3;"+nl+"b:=5;") == nl # optional - magma
546
+ True
547
+ sage: magma.eval("[a,b];") # optional - magma
548
+ '[ 3, 5 ]'
549
+ """
550
+ x = self._preparse(x)
551
+ x = str(x).rstrip()
552
+ if len(x) == 0 or x[len(x) - 1] != ';':
553
+ x += ';'
554
+ ans = Expect.eval(self, x, **kwds).replace('\\\n', '')
555
+ if 'Runtime error' in ans or 'User error' in ans:
556
+ raise RuntimeError("Error evaluating Magma code.\nIN:%s\nOUT:%s" % (x, ans))
557
+ return ans
558
+
559
+ def _preparse(self, s) -> str:
560
+ """
561
+ All input gets preparsed by calling this function before it gets evaluated.
562
+
563
+ EXAMPLES::
564
+
565
+ sage: magma = Magma()
566
+ sage: magma._preparse_colon_equals = False
567
+ sage: magma._preparse('a = 5')
568
+ 'a = 5'
569
+ sage: magma._preparse_colon_equals = True
570
+ sage: magma._preparse('a = 5')
571
+ 'a := 5'
572
+ sage: magma._preparse('a = 5; b := 7; c =a+b;')
573
+ 'a := 5; b := 7; c :=a+b;'
574
+ """
575
+ try:
576
+ # this is in a try/except only because of the possibility
577
+ # of old pickled Magma interfaces.
578
+ if self._preparse_colon_equals:
579
+ s = s.replace(':=', '=').replace('=', ':=')
580
+ except AttributeError:
581
+ pass
582
+ return s
583
+
584
+ def _start(self) -> None:
585
+ """
586
+ Initialize a Magma interface instance. This involves (1) setting up
587
+ an obfuscated prompt, and (2) attaching the MAGMA_SPEC file (see
588
+ EXTCODE_DIR/spec file (see sage.interfaces.magma.EXTCODE_DIR/spec).
589
+
590
+ EXAMPLES: This is not too exciting::
591
+
592
+ sage: magma._start() # optional - magma
593
+ """
594
+ self._change_prompt('>')
595
+ Expect._start(self)
596
+ self.eval('SetPrompt("%s"); SetLineEditor(false); SetColumns(0);' % PROMPT)
597
+ self._change_prompt(PROMPT)
598
+ self.expect().expect(PROMPT)
599
+ self.expect().expect(PROMPT)
600
+ self.expect().expect(PROMPT)
601
+ self.attach_spec(extcode_dir(self) + '/spec')
602
+ # set random seed
603
+ self.set_seed(self._seed)
604
+
605
+ def set(self, var, value):
606
+ """
607
+ Set the variable var to the given value in the Magma interpreter.
608
+
609
+ INPUT:
610
+
611
+ - ``var`` -- string; a variable name
612
+
613
+ - ``value`` -- string; what to set var equal to
614
+
615
+ EXAMPLES::
616
+
617
+ sage: magma.set('abc', '2 + 3/5') # optional - magma
618
+ sage: magma('abc') # optional - magma
619
+ 13/5
620
+ """
621
+ out = self.eval("%s:=%s" % (var, value))
622
+ if out.lower().find("error") != -1:
623
+ raise TypeError("Error executing Magma code:\n%s" % out)
624
+
625
+ def get(self, var) -> str:
626
+ """
627
+ Get the value of the variable var.
628
+
629
+ INPUT:
630
+
631
+ - ``var`` -- string; name of a variable defined in the
632
+ Magma session
633
+
634
+ OUTPUT: string representation of the value of the variable
635
+
636
+ EXAMPLES::
637
+
638
+ sage: magma.set('abc', '2 + 3/5') # optional - magma
639
+ sage: magma.get('abc') # optional - magma
640
+ '13/5'
641
+ """
642
+ return self.eval("%s" % var)
643
+
644
+ def objgens(self, value, gens):
645
+ """
646
+ Create a new object with given value and gens.
647
+
648
+ INPUT:
649
+
650
+ - ``value`` -- something coercible to an element of this Magma
651
+ interface
652
+
653
+ - ``gens`` -- string; comma separated list of variable names
654
+
655
+ OUTPUT: new Magma element that is equal to value with given gens
656
+
657
+ EXAMPLES::
658
+
659
+ sage: R = magma.objgens('PolynomialRing(Rationals(),2)', 'alpha,beta') # optional - magma
660
+ sage: R.gens() # optional - magma
661
+ (alpha, beta)
662
+
663
+ Because of how Magma works you can use this to change the variable
664
+ names of the generators of an object::
665
+
666
+ sage: S = magma.objgens(R, 'X,Y') # optional - magma
667
+ sage: R # optional - magma
668
+ Polynomial ring of rank 2 over Rational Field
669
+ Order: Lexicographical
670
+ Variables: X, Y
671
+ sage: S # optional - magma
672
+ Polynomial ring of rank 2 over Rational Field
673
+ Order: Lexicographical
674
+ Variables: X, Y
675
+ """
676
+ var = self._next_var_name()
677
+ value = self(value)
678
+ out = self.eval("_zsage_<%s> := %s; %s := _zsage_" % (gens,
679
+ value.name(),
680
+ var))
681
+ if out.lower().find("error") != -1:
682
+ raise TypeError("Error executing Magma code:\n%s" % out)
683
+ return self(var)
684
+
685
+ def __call__(self, x, gens=None):
686
+ """
687
+ Coerce x into this Magma interpreter interface.
688
+
689
+ INPUT:
690
+
691
+ - ``x`` -- object
692
+
693
+ - ``gens`` -- string; names of generators of self,
694
+ separated by commas
695
+
696
+ OUTPUT: :class:`MagmaElement`
697
+
698
+ EXAMPLES::
699
+
700
+ sage: # optional - magma
701
+ sage: magma(EllipticCurve('37a'))
702
+ Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
703
+ sage: magma('EllipticCurve([GF(5)|1,2,3,4,1])')
704
+ Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 1 over GF(5)
705
+ sage: magma('PowerSeriesRing(Rationals())', 't')
706
+ Power series ring in t over Rational Field
707
+ sage: magma('PolynomialRing(RationalField(), 3)', 'x,y,z')
708
+ Polynomial ring of rank 3 over Rational Field
709
+ Order: Lexicographical
710
+ Variables: x, y, z
711
+
712
+ We test a coercion between different Magma instances::
713
+
714
+ sage: m = Magma()
715
+ sage: n = Magma()
716
+ sage: a = n(m(2)) # optional - magma
717
+ sage: a.parent() is n # optional - magma
718
+ True
719
+ sage: a.parent() is m # optional - magma
720
+ False
721
+
722
+ We test caching::
723
+
724
+ sage: # optional - magma
725
+ sage: R.<x> = ZZ[]
726
+ sage: magma(R) is magma(R)
727
+ True
728
+ sage: m = Magma()
729
+ sage: m(R)
730
+ Univariate Polynomial Ring in x over Integer Ring
731
+ sage: m(R) is magma(R)
732
+ False
733
+ sage: R._magma_cache
734
+ {Magma: Univariate Polynomial Ring in x over Integer Ring,
735
+ Magma: Univariate Polynomial Ring in x over Integer Ring}
736
+
737
+ sage: # optional - magma
738
+ sage: P.<x,y> = PolynomialRing(GF(127))
739
+ sage: m = Magma()
740
+ sage: m(P)
741
+ Polynomial ring of rank 2 over GF(127)
742
+ Order: Graded Reverse Lexicographical
743
+ Variables: x, y
744
+ sage: P._magma_cache
745
+ {Magma: Polynomial ring of rank 2 over GF(127)
746
+ Order: Graded Reverse Lexicographical
747
+ Variables: x, y}
748
+ """
749
+ if isinstance(x, bool):
750
+ return Expect.__call__(self, 'true' if x else 'false')
751
+
752
+ if gens is not None: # get rid of this at some point -- it's weird
753
+ return self.objgens(x, gens)
754
+
755
+ # This is mostly about caching the Magma element in the object
756
+ # itself below. Note that it is *very* important that caching
757
+ # happen on the object itself, and not in a dictionary that is
758
+ # held by the Magma interface, since we want garbage collection
759
+ # of the objects in the Magma interface to work correctly.
760
+ has_cache = hasattr(x, '_magma_cache')
761
+ try:
762
+ if has_cache and self in x._magma_cache:
763
+ A = x._magma_cache[self]
764
+ if A._session_number == self._session_number:
765
+ return A
766
+ except AttributeError:
767
+ # This happens when x has _magma_cache as a cdef public object attribute.
768
+ x._magma_cache = {}
769
+
770
+ try:
771
+ if x in self.__cache:
772
+ A = self.__cache[x]
773
+ if A._session_number == self._session_number:
774
+ return A
775
+ except TypeError: # if x isn't hashable
776
+ pass
777
+
778
+ A = Expect.__call__(self, x)
779
+ if has_cache:
780
+ x._magma_cache[self] = A
781
+ else:
782
+ try: # use try/except here, because if x is cdef'd we won't be able to set this.
783
+ x._magma_cache = {self: A}
784
+ except AttributeError:
785
+ # Unfortunately, we *have* do have this __cache
786
+ # attribute, which can lead to "leaks" in the working
787
+ # Magma session. This is because it is critical that
788
+ # parent objects get cached, but sometimes they can't
789
+ # be cached in the object itself, because the object
790
+ # doesn't have a _magma_cache attribute. So in such
791
+ # cases when the object is a parent we cache it in
792
+ # the magma interface.
793
+ if isinstance(x, Parent):
794
+ self.__cache[x] = A
795
+ return A
796
+
797
+ def _coerce_from_special_method(self, x):
798
+ """
799
+ Try to coerce to ``self`` by calling a special underscore method.
800
+
801
+ If no such method is defined, raises an :exc:`AttributeError` instead
802
+ of a :exc:`TypeError`.
803
+
804
+ EXAMPLES::
805
+
806
+ sage: magma._coerce_from_special_method(-3/5) # optional - magma
807
+ -3/5
808
+
809
+ Note that AttributeError::
810
+
811
+ sage: magma._coerce_from_special_method('2 + 3') # optional - magma
812
+ Traceback (most recent call last):
813
+ ...
814
+ AttributeError: 'str' object has no attribute '_magma_init_'...
815
+ """
816
+ s = x._magma_init_(self)
817
+ a = self(s)
818
+
819
+ # dereference all _sage_ref's used in this string.
820
+ while True:
821
+ z = SAGE_REF_RE.search(s)
822
+ if not z:
823
+ break
824
+ self.eval('delete %s;' % s[z.start():z.end()])
825
+ s = s[z.end()+1:]
826
+ return a
827
+
828
+ def _with_names(self, s, names):
829
+ """
830
+ Return s but wrapped by a call to SageCreateWithNames. This is just
831
+ a very simple convenience function so that code is cleaner.
832
+
833
+ INPUT:
834
+
835
+ - ``s`` -- string
836
+
837
+ - ``names`` -- list of strings
838
+
839
+ OUTPUT: string
840
+
841
+ EXAMPLES::
842
+
843
+ sage: magma._with_names('PolynomialRing(RationalField())', ['y']) # optional - magma
844
+ 'SageCreateWithNames(PolynomialRing(RationalField()),["y"])'
845
+ """
846
+ return 'SageCreateWithNames(%s,[%s])' % (s, ','.join('"%s"' % x
847
+ for x in names))
848
+
849
+ def clear(self, var):
850
+ """
851
+ Clear the variable named var and make it available to be used
852
+ again.
853
+
854
+ INPUT:
855
+
856
+ - ``var`` -- string
857
+
858
+ EXAMPLES::
859
+
860
+ sage: magma = Magma() # optional - magma
861
+ sage: magma.clear('foo') # sets foo to 0 in magma; optional - magma
862
+ sage: magma.eval('foo') # optional - magma
863
+ '0'
864
+
865
+ Because we cleared foo, it is set to be used as a variable name in
866
+ the future::
867
+
868
+ sage: a = magma('10') # optional - magma
869
+ sage: a.name() # optional - magma
870
+ 'foo'
871
+
872
+ The following tests that the whole variable clearing and freeing
873
+ system is working correctly.
874
+
875
+ ::
876
+
877
+ sage: # optional - magma
878
+ sage: magma = Magma()
879
+ sage: a = magma('100')
880
+ sage: a.name()
881
+ '_sage_[1]'
882
+ sage: del a
883
+ sage: b = magma('257')
884
+ sage: b.name()
885
+ '_sage_[1]'
886
+ sage: del b
887
+ sage: magma('_sage_[1]')
888
+ 0
889
+ """
890
+ self.__available_var.insert(0, var) # adds var to front of list
891
+ self.eval("%s:=0" % var)
892
+
893
+ def cputime(self, t=None):
894
+ """
895
+ Return the CPU time in seconds that has elapsed since this Magma
896
+ session started. This is a floating point number, computed by
897
+ Magma.
898
+
899
+ If t is given, then instead return the floating point time from
900
+ when t seconds had elapsed. This is useful for computing elapsed
901
+ times between two points in a running program.
902
+
903
+ INPUT:
904
+
905
+ - ``t`` -- float (default: ``None``); if not None, return
906
+ cputime since t
907
+
908
+ OUTPUT:
909
+
910
+ - ``float`` -- seconds
911
+
912
+ EXAMPLES::
913
+
914
+ sage: # optional - magma
915
+ sage: type(magma.cputime())
916
+ <... 'float'>
917
+ sage: magma.cputime() # random
918
+ 1.9399999999999999
919
+ sage: t = magma.cputime()
920
+ sage: magma.cputime(t) # random
921
+ 0.02
922
+ """
923
+ if t:
924
+ return float(self.eval('Cputime(%s)' % t))
925
+ return float(self.eval('Cputime()'))
926
+
927
+ def chdir(self, dir):
928
+ """
929
+ Change the Magma interpreter's current working directory.
930
+
931
+ INPUT:
932
+
933
+ - ``dir`` -- string
934
+
935
+ EXAMPLES::
936
+
937
+ sage: magma.chdir('/') # optional - magma
938
+ sage: magma.eval('System("pwd")') # optional - magma
939
+ '/'
940
+ """
941
+ self.eval('ChangeDirectory("%s")' % dir, strip=False)
942
+
943
+ def attach(self, filename):
944
+ r"""
945
+ Attach the given file to the running instance of Magma.
946
+
947
+ Attaching a file in Magma makes all intrinsics defined in the file
948
+ available to the shell. Moreover, if the file doesn't start with
949
+ the ``freeze;`` command, then the file is reloaded
950
+ whenever it is changed. Note that functions and procedures defined
951
+ in the file are *not* available. For only those, use
952
+ ``magma.load(filename)``.
953
+
954
+ INPUT:
955
+
956
+ - ``filename`` -- string
957
+
958
+ EXAMPLES: Attaching a file that exists is fine::
959
+
960
+ sage: SAGE_EXTCODE = SAGE_ENV['SAGE_EXTCODE'] # optional - magma
961
+ sage: magma.attach('%s/magma/sage/basic.m'%SAGE_EXTCODE) # optional - magma
962
+
963
+ Attaching a file that doesn't exist raises an exception::
964
+
965
+ sage: SAGE_EXTCODE = SAGE_ENV['SAGE_EXTCODE'] # optional - magma
966
+ sage: magma.attach('%s/magma/sage/basic2.m'%SAGE_EXTCODE) # optional - magma
967
+ Traceback (most recent call last):
968
+ ...
969
+ RuntimeError: Error evaluating Magma code...
970
+ """
971
+ self.eval('Attach("%s")' % filename)
972
+
973
+ Attach = attach
974
+
975
+ def attach_spec(self, filename):
976
+ r"""
977
+ Attach the given spec file to the running instance of Magma.
978
+
979
+ This can attach numerous other files to the running Magma (see the
980
+ Magma documentation for more details).
981
+
982
+ INPUT:
983
+
984
+ - ``filename`` -- string
985
+
986
+ EXAMPLES::
987
+
988
+ sage: SAGE_EXTCODE = SAGE_ENV['SAGE_EXTCODE'] # optional - magma
989
+ sage: magma.attach_spec('%s/magma/spec'%SAGE_EXTCODE) # optional - magma
990
+ sage: magma.attach_spec('%s/magma/spec2'%SAGE_EXTCODE) # optional - magma
991
+ Traceback (most recent call last):
992
+ ...
993
+ RuntimeError: Can't open package spec file .../magma/spec2 for reading (No such file or directory)
994
+ """
995
+ s = self.eval('AttachSpec("%s")' % filename)
996
+ if s:
997
+ raise RuntimeError(s.strip())
998
+
999
+ AttachSpec = attach_spec
1000
+
1001
+ def load(self, filename):
1002
+ r"""
1003
+ Load the file with given filename using the 'load' command in the
1004
+ Magma shell.
1005
+
1006
+ Loading a file in Magma makes all the functions and procedures in
1007
+ the file available. The file should not contain any intrinsics (or
1008
+ you will get errors). It also runs code in the file, which can
1009
+ produce output.
1010
+
1011
+ INPUT:
1012
+
1013
+ - ``filename`` -- string
1014
+
1015
+ OUTPUT: output printed when loading the file
1016
+
1017
+ EXAMPLES::
1018
+
1019
+ sage: from tempfile import NamedTemporaryFile as NTF
1020
+ sage: with NTF(mode='w+t', suffix='.m') as f: # optional - magma
1021
+ ....: _ = f.write('function f(n) return n^2; end function;\nprint "hi";')
1022
+ ....: print(magma.load(f.name))
1023
+ Loading "....m"
1024
+ hi
1025
+ sage: magma('f(12)') # optional - magma
1026
+ 144
1027
+ """
1028
+ p = Path(filename)
1029
+ return self.eval('load "%s"' % p.absolute())
1030
+
1031
+ def _next_var_name(self) -> str:
1032
+ """
1033
+ Return the next available variable name in Magma.
1034
+
1035
+ OUTPUT: string
1036
+
1037
+ EXAMPLES::
1038
+
1039
+ sage: m = Magma()
1040
+ sage: m._next_var_name() # optional - magma
1041
+ '_sage_[1]'
1042
+ sage: m._next_var_name() # optional - magma
1043
+ '_sage_[2]'
1044
+ sage: a = m(3/8); a # optional - magma
1045
+ 3/8
1046
+ sage: a.name() # optional - magma
1047
+ '_sage_[3]'
1048
+ sage: m._next_var_name() # optional - magma
1049
+ '_sage_[4]'
1050
+ """
1051
+ if self.__seq == 0:
1052
+ self.eval('_sage_ := [* *];')
1053
+ else:
1054
+ try:
1055
+ self.eval('Append(~_sage_, 0);')
1056
+ except Exception:
1057
+ # this exception could happen if the Magma process
1058
+ # was interrupted during startup / initialization.
1059
+ self.eval('_sage_ := [* 0 : i in [1..%s] *];' % self.__seq)
1060
+ try:
1061
+ return self.__available_var.pop()
1062
+ except IndexError:
1063
+ self.__seq += 1
1064
+ return '_sage_[%s]' % self.__seq
1065
+
1066
+ def _next_ref_name(self):
1067
+ """
1068
+ Return the next reference name. This is used internally to deal
1069
+ with Magma objects that would be deallocated before they are used
1070
+ in constructing another object.
1071
+
1072
+ OUTPUT: string
1073
+
1074
+ EXAMPLES::
1075
+
1076
+ sage: magma._next_ref_name()
1077
+ '_sage_ref...'
1078
+ """
1079
+ self.__ref += 1
1080
+ return '%s%s' % (SAGE_REF, self.__ref)
1081
+
1082
+ def function_call(self, function, args=[], params={}, nvals=1):
1083
+ """
1084
+ Return result of evaluating a Magma function with given input,
1085
+ parameters, and asking for nvals as output.
1086
+
1087
+ INPUT:
1088
+
1089
+ - ``function`` -- string, a Magma function name
1090
+
1091
+ - ``args`` -- list of objects coercible into this magma
1092
+ interface
1093
+
1094
+ - ``params`` -- Magma parameters, passed in after a
1095
+ colon
1096
+
1097
+ - ``nvals`` -- number of return values from the
1098
+ function to ask Magma for
1099
+
1100
+ OUTPUT: instance of :class:`MagmaElement` or a tuple of ``nvals`` many
1101
+ :class:`MagmaElement` instances
1102
+
1103
+ EXAMPLES::
1104
+
1105
+ sage: magma.function_call('Factorization', 100) # optional - magma
1106
+ [ <2, 2>, <5, 2> ]
1107
+ sage: magma.function_call('NextPrime', 100, {'Proof':False}) # optional - magma
1108
+ 101
1109
+ sage: magma.function_call('PolynomialRing', [QQ,2]) # optional - magma
1110
+ Polynomial ring of rank 2 over Rational Field
1111
+ Order: Lexicographical
1112
+ Variables: $.1, $.2
1113
+
1114
+ Next, we illustrate multiple return values::
1115
+
1116
+ sage: magma.function_call('IsSquare', 100) # optional - magma
1117
+ true
1118
+ sage: magma.function_call('IsSquare', 100, nvals=2) # optional - magma
1119
+ (true, 10)
1120
+ sage: magma.function_call('IsSquare', 100, nvals=3) # optional - magma
1121
+ Traceback (most recent call last):
1122
+ ...
1123
+ RuntimeError: Error evaluating Magma code...
1124
+ Runtime error in :=: Expected to assign 3 value(s) but only computed 2 value(s)
1125
+ """
1126
+ args, params = self._convert_args_kwds(args, params)
1127
+ nvals = int(nvals)
1128
+ if len(params) == 0:
1129
+ par = ''
1130
+ else:
1131
+ par = ' : ' + ','.join('%s:=%s' % (a, b.name())
1132
+ for a, b in params.items())
1133
+
1134
+ fun = "%s(%s%s)" % (function, ",".join(s.name() for s in args), par)
1135
+
1136
+ return self._do_call(fun, nvals)
1137
+
1138
+ def _do_call(self, code, nvals):
1139
+ """
1140
+ Evaluate the given code expression assuming that it outputs nvals
1141
+ distinct values. Return the resulting values as a tuple if nvals =
1142
+ 2.
1143
+
1144
+ INPUT:
1145
+
1146
+ - ``code`` -- string; code to evaluate
1147
+
1148
+ - ``nvals`` -- integer; number of return values
1149
+
1150
+ OUTPUT: nvals distinct values
1151
+
1152
+ EXAMPLES::
1153
+
1154
+ sage: magma._do_call('SetVerbose("Groebner",2)', 0) # optional - magma
1155
+ sage: magma._do_call('Factorization(-5)', 1) # optional - magma
1156
+ [ <5, 1> ]
1157
+
1158
+ Here we get two outputs, as a tuple.
1159
+
1160
+ ::
1161
+
1162
+ sage: magma._do_call('Factorization(-5)', 2) # optional - magma
1163
+ ([ <5, 1> ], -1)
1164
+
1165
+ You can also do this::
1166
+
1167
+ sage: F, sign = magma._do_call('Factorization(-5)', 2) # optional - magma
1168
+ sage: F # optional - magma
1169
+ [ <5, 1> ]
1170
+ sage: sign # optional - magma
1171
+ -1
1172
+
1173
+ An expression that has one value.
1174
+
1175
+ ::
1176
+
1177
+ sage: magma._do_call('3^5', 1) # optional - magma
1178
+ 243
1179
+ """
1180
+ if nvals <= 0:
1181
+ out = self.eval(code)
1182
+ ans = None
1183
+ elif nvals == 1:
1184
+ return self(code)
1185
+ else:
1186
+ v = [self._next_var_name() for _ in range(nvals)]
1187
+ vars = ", ".join(v)
1188
+ cmd = "%s := %s;" % (vars, code)
1189
+ out = self.eval(cmd)
1190
+ ans = tuple([MagmaElement(self, x, is_name=True) for x in v])
1191
+
1192
+ if out.lower().find("error") != -1:
1193
+ raise TypeError("Error executing Magma code:\n%s" % out)
1194
+ return ans
1195
+
1196
+ def bar_call(self, left, name, gens, nvals=1):
1197
+ """
1198
+ This is a wrapper around the Magma constructor.
1199
+
1200
+ nameleft gens
1201
+
1202
+ returning nvals.
1203
+
1204
+ INPUT:
1205
+
1206
+ - ``left`` -- something coerceable to a magma object
1207
+
1208
+ - ``name`` -- name of the constructor, e.g., sub, quo,
1209
+ ideal, etc.
1210
+
1211
+ - ``gens`` -- if a list/tuple, each item is coerced to
1212
+ magma; otherwise gens itself is converted to magma
1213
+
1214
+ - ``nvals`` -- positive integer; number of return
1215
+ values
1216
+
1217
+ OUTPUT: a single magma object if nvals == 1; otherwise a tuple of
1218
+ nvals magma objects.
1219
+
1220
+ EXAMPLES: The bar_call function is used by the sub, quo, and ideal
1221
+ methods of Magma elements. Here we illustrate directly using
1222
+ bar_call to create quotients::
1223
+
1224
+ sage: # optional - magma
1225
+ sage: V = magma.RModule(ZZ,3)
1226
+ sage: V
1227
+ RModule(IntegerRing(), 3)
1228
+ sage: magma.bar_call(V, 'quo', [[1,2,3]], nvals=1)
1229
+ RModule(IntegerRing(), 2)
1230
+ sage: magma.bar_call(V, 'quo', [[1,2,3]], nvals=2)
1231
+ (RModule(IntegerRing(), 2),
1232
+ Mapping from: RModule(IntegerRing(), 3) to RModule(IntegerRing(), 2))
1233
+ sage: magma.bar_call(V, 'quo', V, nvals=2)
1234
+ (RModule(IntegerRing(), 0),
1235
+ Mapping from: RModule(IntegerRing(), 3) to RModule(IntegerRing(), 0))
1236
+ """
1237
+ magma = self
1238
+ # coerce each arg to be a Magma element
1239
+ if isinstance(gens, (list, tuple)):
1240
+ gens = [magma(z) for z in gens]
1241
+ # make comma separated list of names (in Magma) of each of the gens
1242
+ v = ', '.join(w.name() for w in gens)
1243
+ else:
1244
+ gens = magma(gens)
1245
+ v = gens.name()
1246
+ # construct the string that evaluates in Magma to define the subobject,
1247
+ # and return it evaluated in Magma.
1248
+ s = '%s< %s | %s >' % (name, left.name(), v)
1249
+ return self._do_call(s, nvals)
1250
+
1251
+ def _object_class(self):
1252
+ """
1253
+ Return the Python class of elements of the Magma interface.
1254
+
1255
+ OUTPUT: a Python class
1256
+
1257
+ EXAMPLES::
1258
+
1259
+ sage: magma._object_class()
1260
+ <class 'sage.interfaces.magma.MagmaElement'>
1261
+ """
1262
+ return MagmaElement
1263
+
1264
+ # Usually "Sequences" are what you want in Magma, not "lists".
1265
+ # It's very painful using the interface without this.
1266
+ def _left_list_delim(self):
1267
+ """
1268
+ Return the left sequence delimiter in Magma.
1269
+
1270
+ Despite the name in this function, this is really the least
1271
+ painful choice.
1272
+
1273
+ EXAMPLES::
1274
+
1275
+ sage: magma._left_list_delim()
1276
+ '['
1277
+ """
1278
+ return "["
1279
+
1280
+ def _right_list_delim(self):
1281
+ """
1282
+ Return the right sequence delimiter in Magma.
1283
+
1284
+ Despite the name in this function, this is really the least
1285
+ painful choice.
1286
+
1287
+ EXAMPLES::
1288
+
1289
+ sage: magma._right_list_delim()
1290
+ ']'
1291
+ """
1292
+ return "]"
1293
+
1294
+ def _assign_symbol(self):
1295
+ """
1296
+ Return the assignment symbol in Magma.
1297
+
1298
+ EXAMPLES::
1299
+
1300
+ sage: magma._assign_symbol()
1301
+ ':='
1302
+ """
1303
+ return ":="
1304
+
1305
+ def _equality_symbol(self):
1306
+ """
1307
+ Return the equality testing logical symbol in Magma.
1308
+
1309
+ EXAMPLES::
1310
+
1311
+ sage: magma._equality_symbol()
1312
+ 'eq'
1313
+ """
1314
+ return 'eq'
1315
+
1316
+ def _lessthan_symbol(self):
1317
+ """
1318
+ Return the less than testing logical symbol in Magma.
1319
+
1320
+ EXAMPLES::
1321
+
1322
+ sage: magma._lessthan_symbol()
1323
+ ' lt '
1324
+ """
1325
+ return ' lt '
1326
+
1327
+ def _greaterthan_symbol(self):
1328
+ """
1329
+ Return the greater than testing logical symbol in Magma.
1330
+
1331
+ EXAMPLES::
1332
+
1333
+ sage: magma._greaterthan_symbol()
1334
+ ' gt '
1335
+ """
1336
+ return ' gt '
1337
+
1338
+ # For efficiency purposes, you should definitely override these
1339
+ # in your derived class.
1340
+ def _true_symbol(self):
1341
+ """
1342
+ Return the string representation of "truth" in Magma.
1343
+
1344
+ EXAMPLES::
1345
+
1346
+ sage: magma._true_symbol()
1347
+ 'true'
1348
+ """
1349
+ return 'true'
1350
+
1351
+ def _false_symbol(self):
1352
+ """
1353
+ Return the string representation of "false" in Magma.
1354
+
1355
+ EXAMPLES::
1356
+
1357
+ sage: magma._false_symbol()
1358
+ 'false'
1359
+ """
1360
+ return 'false'
1361
+
1362
+ def console(self):
1363
+ """
1364
+ Run a command line Magma session. This session is completely
1365
+ separate from this Magma interface.
1366
+
1367
+ EXAMPLES::
1368
+
1369
+ sage: magma.console() # not tested
1370
+ Magma V2.14-9 Sat Oct 11 2008 06:36:41 on one [Seed = 1157408761]
1371
+ Type ? for help. Type <Ctrl>-D to quit.
1372
+ >
1373
+ Total time: 2.820 seconds, Total memory usage: 3.95MB
1374
+ """
1375
+ magma_console()
1376
+
1377
+ def version(self):
1378
+ """
1379
+ Return the version of Magma that you have in your PATH on your
1380
+ computer.
1381
+
1382
+ OUTPUT:
1383
+
1384
+ - ``numbers`` -- 3-tuple: major, minor, etc.
1385
+
1386
+ - ``string`` -- version as a string
1387
+
1388
+ EXAMPLES::
1389
+
1390
+ sage: magma.version() # random, optional - magma
1391
+ ((2, 14, 9), 'V2.14-9')
1392
+ """
1393
+ t = tuple([int(n) for n in self.eval('GetVersion()').split()])
1394
+ return t, 'V%s.%s-%s' % t
1395
+
1396
+ def help(self, s):
1397
+ """
1398
+ Return Magma help on string s.
1399
+
1400
+ This returns what typing ?s would return in Magma.
1401
+
1402
+ INPUT:
1403
+
1404
+ - ``s`` -- string
1405
+
1406
+ OUTPUT: string
1407
+
1408
+ EXAMPLES::
1409
+
1410
+ sage: magma.help("NextPrime") # optional - magma
1411
+ ===============================================================================
1412
+ PATH: /magma/ring-field-algebra/integer/prime/next-previous/NextPrime
1413
+ KIND: Intrinsic
1414
+ ===============================================================================
1415
+ NextPrime(n) : RngIntElt -> RngIntElt
1416
+ NextPrime(n: parameter) : RngIntElt -> RngIntElt
1417
+ ...
1418
+ """
1419
+ print(self.eval('? %s' % s))
1420
+
1421
+ def _tab_completion(self, verbose=True, use_disk_cache=True):
1422
+ """
1423
+ Return a list of all Magma commands.
1424
+
1425
+ This is used as a hook to enable custom command completion.
1426
+
1427
+ Magma doesn't provide any fast way to make a list of all commands,
1428
+ which is why caching is done by default. Note that an adverse
1429
+ impact of caching is that *new* commands are not picked up, e.g.,
1430
+ user defined variables or functions.
1431
+
1432
+ INPUT:
1433
+
1434
+ - ``verbose`` -- boolean (default: ``True``); whether to
1435
+ verbosely output status info the first time the command list is
1436
+ built
1437
+
1438
+ - ``use_disk_cache`` -- boolean (default: ``True``); use
1439
+ cached command list, which is saved to disk
1440
+
1441
+ OUTPUT: list of strings
1442
+
1443
+ EXAMPLES::
1444
+
1445
+ sage: len(magma._tab_completion(verbose=False)) # random, optional - magma
1446
+ 7261
1447
+ """
1448
+ try:
1449
+ return self.__tab_completion
1450
+ except AttributeError:
1451
+ import sage.misc.persist
1452
+ if use_disk_cache:
1453
+ try:
1454
+ self.__tab_completion = sage.misc.persist.load(INTRINSIC_CACHE)
1455
+ return self.__tab_completion
1456
+ except OSError:
1457
+ pass
1458
+ if verbose:
1459
+ print("\nCreating list of all Magma intrinsics for use in tab completion.")
1460
+ print("This takes a few minutes the first time, but is saved to the")
1461
+ print("file '%s' for future instant use." % INTRINSIC_CACHE)
1462
+ print("Magma may produce errors during this process, which are safe to ignore.")
1463
+ print("Delete that file to force recreation of this cache.")
1464
+ print("Scanning Magma types ...")
1465
+ tm = sage.misc.misc.cputime()
1466
+ T = self.eval('ListTypes()').split()
1467
+ N = []
1468
+ for t in T:
1469
+ if verbose:
1470
+ print(t, " ", end="")
1471
+ sys.stdout.flush()
1472
+ try:
1473
+ s = self.eval('ListSignatures(%s)' % t)
1474
+ for x in s.split('\n'):
1475
+ i = x.find('(')
1476
+ N.append(x[:i])
1477
+ except RuntimeError as msg: # weird internal problems in Magma type system
1478
+ print('Error -- %s' % msg)
1479
+ if verbose:
1480
+ print("Done! (%s seconds)" % sage.misc.misc.cputime(tm))
1481
+ N = sorted(set(N))
1482
+ print("Saving cache to '%s' for future instant use." % INTRINSIC_CACHE)
1483
+ print("Delete the above file to force re-creation of the cache.")
1484
+ sage.misc.persist.save(N, INTRINSIC_CACHE)
1485
+ self.__tab_completion = N
1486
+ return N
1487
+
1488
+ def ideal(self, L):
1489
+ """
1490
+ Return the Magma ideal defined by L.
1491
+
1492
+ INPUT:
1493
+
1494
+ - ``L`` -- list of elements of a Sage multivariate
1495
+ polynomial ring
1496
+
1497
+ OUTPUT: the magma ideal generated by the elements of L
1498
+
1499
+ EXAMPLES::
1500
+
1501
+ sage: R.<x,y> = QQ[]
1502
+ sage: magma.ideal([x^2, y^3*x]) # optional - magma
1503
+ Ideal of Polynomial ring of rank 2 over Rational Field
1504
+ Order: Graded Reverse Lexicographical
1505
+ Variables: x, y
1506
+ Homogeneous
1507
+ Basis:
1508
+ [
1509
+ x^2,
1510
+ x*y^3
1511
+ ]
1512
+ """
1513
+ P = next(iter(L)).parent()
1514
+ Pn = self(P).name()
1515
+ k = P.base_ring()
1516
+ if k.degree() > 1:
1517
+ i = str(k.gen())
1518
+ o = self("BaseRing(%s).1" % Pn).name()
1519
+ self.eval("%s := %s" % (i, o))
1520
+ mlist = self(L)
1521
+ return self("ideal<%s|%s>" % (Pn, mlist.name()))
1522
+
1523
+ def set_verbose(self, type, level):
1524
+ """
1525
+ Set the verbosity level for a given algorithm, class, etc. in
1526
+ Magma.
1527
+
1528
+ INPUT:
1529
+
1530
+ - ``type`` -- string (e.g. 'Groebner')
1531
+
1532
+ - ``level`` -- integer >= 0
1533
+
1534
+ EXAMPLES::
1535
+
1536
+ sage: magma.set_verbose("Groebner", 2) # optional - magma
1537
+ sage: magma.get_verbose("Groebner") # optional - magma
1538
+ 2
1539
+ """
1540
+ if level < 0:
1541
+ raise TypeError("level must be >= 0")
1542
+ self.eval('SetVerbose("%s",%d)' % (type, level))
1543
+
1544
+ SetVerbose = set_verbose
1545
+
1546
+ def get_verbose(self, type):
1547
+ """
1548
+ Get the verbosity level of a given algorithm class etc. in Magma.
1549
+
1550
+ INPUT:
1551
+
1552
+ - ``type`` -- string (e.g. 'Groebner'), see Magma
1553
+ documentation
1554
+
1555
+ EXAMPLES::
1556
+
1557
+ sage: magma.set_verbose("Groebner", 2) # optional - magma
1558
+ sage: magma.get_verbose("Groebner") # optional - magma
1559
+ 2
1560
+ """
1561
+ return int(self.eval('GetVerbose("%s")' % type))
1562
+
1563
+ GetVerbose = get_verbose
1564
+
1565
+ def set_nthreads(self, n):
1566
+ """
1567
+ Set the number of threads used for parallelized algorithms in Magma.
1568
+
1569
+ INPUT:
1570
+
1571
+ - ``n`` -- number of threads
1572
+
1573
+ EXAMPLES::
1574
+
1575
+ sage: magma.set_nthreads(2) #optional - magma
1576
+ sage: magma.get_nthreads() #optional - magma
1577
+ 2
1578
+ """
1579
+ if n < 1:
1580
+ raise TypeError("no. of threads must be >= 1")
1581
+ self.eval('SetNthreads(%d)' % (n))
1582
+
1583
+ SetNthreads = set_nthreads
1584
+
1585
+ def get_nthreads(self):
1586
+ """
1587
+ Get the number of threads used in Magma.
1588
+
1589
+ EXAMPLES::
1590
+
1591
+ sage: magma.set_nthreads(2) #optional - magma
1592
+ sage: magma.get_nthreads() #optional - magma
1593
+ 2
1594
+ """
1595
+ return int(self.eval('GetNthreads()'))
1596
+
1597
+ GetNthreads = get_nthreads
1598
+
1599
+
1600
+ @instancedoc
1601
+ class MagmaFunctionElement(FunctionElement):
1602
+ def __call__(self, *args, **kwds):
1603
+ """
1604
+ Return the result of calling this Magma function at given inputs.
1605
+
1606
+ Use the optional nvals keyword argument to specify that there are
1607
+ multiple return values.
1608
+
1609
+ EXAMPLES: We create a MagmaFunctionElement::
1610
+
1611
+ sage: # optional - magma
1612
+ sage: n = magma(-15)
1613
+ sage: f = n.Factorisation
1614
+ sage: type(f)
1615
+ <class 'sage.interfaces.magma.MagmaFunctionElement'>
1616
+ sage: f()
1617
+ [ <3, 1>, <5, 1> ]
1618
+
1619
+ We verify that the nvals argument works.
1620
+
1621
+ ::
1622
+
1623
+ sage: f(nvals=2) # optional - magma
1624
+ ([ <3, 1>, <5, 1> ], -1)
1625
+
1626
+ This illustrates the more conventional way of calling a method on
1627
+ an object. It's equivalent to the above, but done in all in one
1628
+ step.
1629
+
1630
+ ::
1631
+
1632
+ sage: n.Factorization(nvals = 2) # optional - magma
1633
+ ([ <3, 1>, <5, 1> ], -1)
1634
+ """
1635
+ nvals = 1
1636
+ if len(kwds) > 0:
1637
+ if 'nvals' in kwds:
1638
+ nvals = kwds['nvals']
1639
+ del kwds['nvals']
1640
+ M = self._obj.parent()
1641
+ return M.function_call(self._name,
1642
+ [self._obj.name()] + list(args),
1643
+ params=kwds,
1644
+ nvals=nvals)
1645
+
1646
+ def _instancedoc_(self):
1647
+ """
1648
+ Return the docstring for this function of an element.
1649
+
1650
+ OUTPUT: string
1651
+
1652
+ EXAMPLES::
1653
+
1654
+ sage: # optional - magma
1655
+ sage: n = magma(-15)
1656
+ sage: f = n.Factorisation
1657
+ sage: print(f.__doc__)
1658
+ (n::RngIntElt) -> RngIntEltFact, RngIntElt, SeqEnum
1659
+ ...
1660
+ sage: print(n.Factorisation.__doc__)
1661
+ (n::RngIntElt) -> RngIntEltFact, RngIntElt, SeqEnum
1662
+ ...
1663
+ """
1664
+ M = self._obj.parent()
1665
+ t = str(self._obj.Type())
1666
+ s = M.eval(self._name)
1667
+ Z = s.split('\n(')[1:]
1668
+ W = []
1669
+ tt = '::%s' % t
1670
+ for X in Z:
1671
+ X = '(' + X
1672
+ if '(<All>' in X or tt in X:
1673
+ W.append(X)
1674
+ s = '\n'.join(W)
1675
+ s = sage.misc.misc.word_wrap(s)
1676
+ return s
1677
+
1678
+ def _repr_(self):
1679
+ """
1680
+ Return string representation of this partially evaluated function.
1681
+
1682
+ This is basically the docstring (as returned by ``_instancedoc_``)
1683
+ unless self._name is the name of an attribute of the object, in
1684
+ which case this returns the value of that attribute.
1685
+
1686
+ EXAMPLES::
1687
+
1688
+ sage: magma(-15).Factorisation # optional - magma
1689
+ Partially evaluated Magma function or intrinsic 'Factorisation'
1690
+ ...
1691
+
1692
+ We create a vector space, set its M attribute to a number, then
1693
+ display/get the attribute as a string.
1694
+
1695
+ ::
1696
+
1697
+ sage: # optional - magma
1698
+ sage: V = magma('VectorSpace(RationalField(),2)')
1699
+ sage: V.set_magma_attribute('M', 290398)
1700
+ sage: V.M
1701
+ 290398
1702
+ sage: type(V.M)
1703
+ <class 'sage.interfaces.magma.MagmaFunctionElement'>
1704
+ sage: type(V.M.__repr__())
1705
+ <... 'str'>
1706
+
1707
+ Displaying a non-attribute function works as above.
1708
+
1709
+ ::
1710
+
1711
+ sage: V.Dimension # optional - magma
1712
+ Partially evaluated Magma function or intrinsic 'Dimension'
1713
+ ...
1714
+ """
1715
+ M = self._obj.parent()
1716
+ try:
1717
+ return M.eval('%s`%s' % (self._obj.name(), self._name))
1718
+ except RuntimeError:
1719
+ return "Partially evaluated Magma function or intrinsic '%s'\n\nSignature:\n\n%s" % (self._name, self._instancedoc_())
1720
+
1721
+
1722
+ @instancedoc
1723
+ class MagmaFunction(ExpectFunction):
1724
+ def __call__(self, *args, **kwds):
1725
+ """
1726
+ Return the result of calling this Magma function at given inputs.
1727
+
1728
+ Use the optional nvals keyword argument to specify that there are
1729
+ multiple return values.
1730
+
1731
+ EXAMPLES: We create a MagmaFunction::
1732
+
1733
+ sage: f = magma.Factorisation # optional - magma
1734
+ sage: type(f) # optional - magma
1735
+ <class 'sage.interfaces.magma.MagmaFunction'>
1736
+ sage: f(-15) # optional - magma
1737
+ [ <3, 1>, <5, 1> ]
1738
+
1739
+ We verify that the nvals argument works.
1740
+
1741
+ ::
1742
+
1743
+ sage: f(-15, nvals=2) # optional - magma
1744
+ ([ <3, 1>, <5, 1> ], -1)
1745
+ sage: f.__call__(-15, nvals=2) # optional - magma
1746
+ ([ <3, 1>, <5, 1> ], -1)
1747
+ """
1748
+ nvals = 1
1749
+ if len(kwds) > 0:
1750
+ if 'nvals' in kwds:
1751
+ nvals = kwds['nvals']
1752
+ del kwds['nvals']
1753
+ M = self._parent
1754
+ return M.function_call(self._name,
1755
+ list(args),
1756
+ params=kwds,
1757
+ nvals=nvals)
1758
+
1759
+ def _instancedoc_(self):
1760
+ """
1761
+ Return docstring about this function.
1762
+
1763
+ OUTPUT: string
1764
+
1765
+ EXAMPLES::
1766
+
1767
+ sage: f = magma.Factorisation
1768
+ sage: type(f)
1769
+ <class 'sage.interfaces.magma.MagmaFunction'>
1770
+ sage: print(f.__doc__) # optional - magma
1771
+ Intrinsic 'Factorisation'
1772
+ ...
1773
+ """
1774
+ M = self._parent
1775
+ s = M.eval(self._name)
1776
+ s = sage.misc.misc.word_wrap(s, 80)
1777
+ return s
1778
+
1779
+
1780
+ @instancedoc
1781
+ class MagmaElement(ExtraTabCompletion, ExpectElement,
1782
+ sage.interfaces.abc.MagmaElement):
1783
+ def _ref(self):
1784
+ """
1785
+ Return a variable name that is a new reference to this particular
1786
+ MagmaElement in Magma. This keeps this object from being garbage
1787
+ collected by Magma, even if all the Sage references to it are
1788
+ freed.
1789
+
1790
+ Important special behavior: When _ref is used during an implicit
1791
+ call to _magma_init_, then the reference disappears after the
1792
+ coercion is done. More precisely, if the output of _ref() appears
1793
+ as part of the output of a call to _magma_init_ that is then
1794
+ going to be input to magma(...), then it is deleted in the Magma
1795
+ interface. The main use for this behavior is that in
1796
+ _magma_init_ it allows you to get a reference to one object, and
1797
+ use it exactly once in constructing a string to evaluate in Magma,
1798
+ without having to worry about that object being deallocated. There
1799
+ are more sophisticated ways that the same problem (with
1800
+ _magma_init_ and references) could have been solved, but this
1801
+ solution is much simpler and easier to understand than all others I
1802
+ came up with. If this doesn't make sense, read the source code to
1803
+ _coerce_from_special_method, which is much shorter than this
1804
+ paragraph.
1805
+
1806
+ .. warning::
1807
+
1808
+ Use _ref sparingly, since it involves a full call to Magma,
1809
+ which can be slow.
1810
+
1811
+ OUTPUT: string
1812
+
1813
+ EXAMPLES::
1814
+
1815
+ sage: a = magma('-2/3') # optional - magma
1816
+ sage: s = a._ref(); s # optional - magma
1817
+ '_sage_ref...'
1818
+ sage: magma(s) # optional - magma
1819
+ -2/3
1820
+ """
1821
+ P = self._check_valid()
1822
+ n = P._next_ref_name()
1823
+ P.set(n, self.name())
1824
+ return n
1825
+
1826
+ def __getattr__(self, attrname):
1827
+ """
1828
+ INPUT:
1829
+
1830
+ - ``attrname`` -- string
1831
+
1832
+ OUTPUT: a Magma function partially evaluated with ``self`` as the first
1833
+ input
1834
+
1835
+ .. NOTE::
1836
+
1837
+ If the input ``attrname`` starts with an underscore, an
1838
+ :exc:`AttributeError` is raised so that the actual
1839
+ Python _ method/value can be accessed.
1840
+
1841
+ EXAMPLES::
1842
+
1843
+ sage: # optional - magma
1844
+ sage: n = magma(-15)
1845
+ sage: type(n)
1846
+ <class 'sage.interfaces.magma.MagmaElement'>
1847
+ sage: f = n.__getattr__('Factorization')
1848
+ sage: type(f)
1849
+ <class 'sage.interfaces.magma.MagmaFunctionElement'>
1850
+ sage: f
1851
+ Partially evaluated Magma function or intrinsic 'Factorization'
1852
+ ...
1853
+ """
1854
+ if attrname[:1] == "_":
1855
+ raise AttributeError
1856
+ return MagmaFunctionElement(self, attrname)
1857
+
1858
+ def _sage_(self):
1859
+ """
1860
+ Return Sage version of this object.
1861
+
1862
+ Use self.sage() to get the Sage version.
1863
+
1864
+ Edit ``src/sage/ext_data/magma/sage/basic.m`` to add functionality.
1865
+
1866
+ EXAMPLES: Enumerated Sets::
1867
+
1868
+ sage: # optional - magma
1869
+ sage: a = magma('{1,2/3,-5/9}')
1870
+ sage: a.sage()
1871
+ {1, -5/9, 2/3}
1872
+ sage: a._sage_()
1873
+ {1, -5/9, 2/3}
1874
+ sage: type(a.sage())
1875
+ <class 'sage.sets.set.Set_object_enumerated_with_category'>
1876
+ sage: a = magma('{1,2/3,-5/9}'); a
1877
+ { -5/9, 2/3, 1 }
1878
+ sage: a.Type()
1879
+ SetEnum
1880
+ sage: b = a.sage(); b
1881
+ {1, -5/9, 2/3}
1882
+ sage: type(b)
1883
+ <class 'sage.sets.set.Set_object_enumerated_with_category'>
1884
+ sage: c = magma(b); c
1885
+ { -5/9, 2/3, 1 }
1886
+ sage: c.Type()
1887
+ SetEnum
1888
+
1889
+ Multisets are converted to lists::
1890
+
1891
+ sage: m = magma('{* 1,2,2,2,4^^2,3 *}') # optional - magma
1892
+ sage: z = m.sage(); z # optional - magma
1893
+ [1, 2, 2, 2, 3, 4, 4]
1894
+ sage: type(z) # optional - magma
1895
+ <... 'list'>
1896
+
1897
+ Tuples get converted to tuples::
1898
+
1899
+ sage: m = magma('<1,2,<3>>') # optional - magma
1900
+ sage: z = m.sage(); z # optional - magma
1901
+ (1, 2, (3,))
1902
+ sage: type(z) # optional - magma
1903
+ <... 'tuple'>
1904
+
1905
+ Sequences get converted to lists::
1906
+
1907
+ sage: m = magma('[<1>,<2>]') # optional - magma
1908
+ sage: z = m.sage(); z # optional - magma
1909
+ [(1,), (2,)]
1910
+ sage: type(z) # optional - magma
1911
+ <... 'list'>
1912
+
1913
+ Matrices::
1914
+
1915
+ sage: a = matrix(ZZ,3,3,[1..9])
1916
+ sage: m = magma(a) # optional - magma
1917
+ sage: b = m.sage(); b # optional - magma
1918
+ [1 2 3]
1919
+ [4 5 6]
1920
+ [7 8 9]
1921
+ sage: b == a # optional - magma
1922
+ True
1923
+
1924
+ A nonsquare matrix::
1925
+
1926
+ sage: a = matrix(ZZ,2,3,[1..6])
1927
+ sage: m = magma(a) # optional - magma
1928
+ sage: m.sage() # optional - magma
1929
+ [1 2 3]
1930
+ [4 5 6]
1931
+
1932
+ Multivariate polynomials::
1933
+
1934
+ sage: # optional - magma
1935
+ sage: R.<x,y,z> = QQ[]
1936
+ sage: f = x^2+3*y
1937
+ sage: g = magma(f).sage(); g
1938
+ x^2 + 3*y
1939
+ sage: parent(f) == parent(g)
1940
+ True
1941
+
1942
+ Real and complex numbers::
1943
+
1944
+ sage: # optional - magma
1945
+ sage: m = magma(RealField(200)(1/3))
1946
+ sage: m.sage()
1947
+ 0.33333333333333333333333333333333333333333333333333333333333
1948
+ sage: m = magma(RealField(1000)(1/3))
1949
+ sage: m.sage()
1950
+ 0.333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333
1951
+
1952
+ sage: m = magma(ComplexField(200)).1; m # optional - magma
1953
+ 1.00000000000000000000000000000000000000000000000000000000000*$.1
1954
+ sage: s = m.Sqrt(); s # optional - magma
1955
+ 0.707106781186547524400844362104849039284835937688474036588340 + 0.707106781186547524400844362104849039284835937688474036588340*$.1
1956
+ sage: s.sage() # indirect doctest, optional - magma
1957
+ 0.70710678118654752440084436210484903928483593768847403658834 + 0.70710678118654752440084436210484903928483593768847403658834*I
1958
+
1959
+ Number fields and their elements::
1960
+
1961
+ sage: x = var('x')
1962
+ sage: L.<alpha> = NumberField(x^3+2*x+2)
1963
+ sage: K = magma(L) # optional - magma
1964
+ sage: K.sage() # optional - magma
1965
+ Number Field in alpha with defining polynomial x^3 + 2*x + 2
1966
+ sage: K.sage() is L # optional - magma
1967
+ True
1968
+ sage: magma(alpha).sage() # optional - magma
1969
+ alpha
1970
+
1971
+ Relative number field elements can be converted from Magma
1972
+ to Sage, but the other direction has not yet been implemented.::
1973
+
1974
+ sage: # needs sage.libs.pari
1975
+ sage: P.<y> = L[]
1976
+ sage: N.<b> = NumberField(y^2-alpha)
1977
+ sage: M = magma(N) # optional - magma
1978
+ sage: M.1.sage() # optional - magma
1979
+ b
1980
+ sage: _^2 # optional - magma
1981
+ alpha
1982
+ sage: magma(b) # optional - magma
1983
+ Traceback (most recent call last):
1984
+ ...
1985
+ TypeError: coercion of relative number field elements to Magma is not implemented
1986
+
1987
+ Sage does not have absolute number fields defined by
1988
+ two polynomials, like Magma does. They are converted
1989
+ to relative number fields. Conversion of their elements
1990
+ has not yet been implemented.::
1991
+
1992
+ sage: # optional - magma
1993
+ sage: magma.eval('P<x> := PolynomialRing(Rationals());')
1994
+ ''
1995
+ sage: K = magma('NumberField([x^2-2,x^2-3]:Abs);')
1996
+ sage: L = K.sage(); L
1997
+ Number Field in K1 with defining polynomial x^2 - 2 over its base field
1998
+ sage: L.base_field()
1999
+ Number Field in K2 with defining polynomial x^2 - 3
2000
+ sage: K.GeneratorsSequence()[1].sage()
2001
+ Traceback (most recent call last):
2002
+ ...
2003
+ NameError: name 'K' is not defined
2004
+
2005
+ Finite quotients of ZZ::
2006
+
2007
+ sage: R = Zmod(137)
2008
+ sage: magma(R).sage() # optional - magma
2009
+ Ring of integers modulo 137
2010
+
2011
+ TESTS:
2012
+
2013
+ Tests for :issue:`30341`::
2014
+
2015
+ sage: P.<t> = PolynomialRing(QQ)
2016
+ sage: l = [-27563611963/4251528, -48034411/104976, -257/54, 1]
2017
+ sage: u = P(l)
2018
+ sage: u == P(magma(u).sage()) # optional - magma
2019
+ True
2020
+
2021
+ sage: P.<x,y> = PolynomialRing(QQ, 2)
2022
+ sage: u = x + 27563611963/4251528*y
2023
+ sage: magma(u).sage() # optional - magma
2024
+ x + 27563611963/4251528*y
2025
+ """
2026
+ z, preparse = self.Sage(nvals=2)
2027
+ s = str(z)
2028
+ preparse = str(preparse) == 'true'
2029
+ return sage.misc.sage_eval.sage_eval(s, preparse=preparse)
2030
+
2031
+ def AssignNames(self, names):
2032
+ """
2033
+ EXAMPLES::
2034
+
2035
+ sage: # optional - magma
2036
+ sage: S = magma.PolynomialRing(magma.Integers(), 2)
2037
+ sage: S.AssignNames(['a', 'b'])
2038
+ sage: S.1
2039
+ a
2040
+ sage: S.1^2 + S.2
2041
+ a^2 + b
2042
+ """
2043
+ P = self._check_valid()
2044
+ cmd = 'AssignNames(~%s, [%s])' % (self.name(),
2045
+ ','.join('"%s"' % x for x in names))
2046
+ P.eval(cmd)
2047
+
2048
+ assign_names = AssignNames
2049
+
2050
+ def gen(self, n):
2051
+ """
2052
+ Return the `n`-th generator of this Magma element.
2053
+
2054
+ Note that generators are 1-based in Magma rather than 0-based!
2055
+
2056
+ INPUT:
2057
+
2058
+ - ``n`` -- *positive* integer
2059
+
2060
+ OUTPUT: :class:`MagmaElement`
2061
+
2062
+ EXAMPLES::
2063
+
2064
+ sage: # needs sage.rings.finite_rings
2065
+ sage: k.<a> = GF(9)
2066
+ sage: magma(k).gen(1) # optional -- magma
2067
+ a
2068
+ sage: R.<s,t,w> = k[]
2069
+ sage: m = magma(R) # optional -- magma
2070
+ sage: m.gen(1) # optional -- magma
2071
+ s
2072
+ sage: m.gen(2) # optional -- magma
2073
+ t
2074
+ sage: m.gen(3) # optional -- magma
2075
+ w
2076
+ sage: m.gen(0) # optional -- magma
2077
+ Traceback (most recent call last):
2078
+ ...
2079
+ IndexError: index must be positive since Magma indexes are 1-based
2080
+ sage: m.gen(4) # optional -- magma
2081
+ Traceback (most recent call last):
2082
+ ...
2083
+ IndexError: tuple index out of range
2084
+ """
2085
+ if n <= 0:
2086
+ raise IndexError("index must be positive since Magma indexes are 1-based")
2087
+ return self.gens()[n - 1]
2088
+
2089
+ def gens(self) -> tuple:
2090
+ """
2091
+ Return generators for ``self``.
2092
+
2093
+ If ``self`` is named X in Magma, this function evaluates X.1, X.2,
2094
+ etc., in Magma until an error occurs. It then returns a Sage tuple
2095
+ of the resulting X.i. Note - I do not think there is a Magma command
2096
+ that returns the list of valid X.i. There are numerous ad hoc
2097
+ functions for various classes but nothing systematic. This function
2098
+ gets around that problem. Again, this is something that should
2099
+ probably be reported to the Magma group and fixed there.
2100
+
2101
+ AUTHORS:
2102
+
2103
+ - William Stein (2006-07-02)
2104
+
2105
+ EXAMPLES::
2106
+
2107
+ sage: magma("VectorSpace(RationalField(),3)").gens() # optional - magma
2108
+ ((1 0 0), (0 1 0), (0 0 1))
2109
+ sage: magma("AbelianGroup(EllipticCurve([1..5]))").gens() # optional - magma
2110
+ ($.1,)
2111
+ """
2112
+ try:
2113
+ return self._magma_gens
2114
+ except AttributeError:
2115
+ pass
2116
+ G = []
2117
+ i = 1
2118
+ P = self._check_valid()
2119
+ n = self.name()
2120
+ while True:
2121
+ try:
2122
+ G.append(P('%s.%s' % (n, i)))
2123
+ except (RuntimeError, TypeError):
2124
+ break
2125
+ i += 1
2126
+ tG = tuple(G)
2127
+ self._magma_gens = tG
2128
+ return tG
2129
+
2130
+ def gen_names(self):
2131
+ """
2132
+ Return list of Magma variable names of the generators of ``self``.
2133
+
2134
+ .. NOTE::
2135
+
2136
+ As illustrated below, these are not the print names of the
2137
+ the generators of the Magma object, but special variable
2138
+ names in the Magma session that reference the generators.
2139
+
2140
+ EXAMPLES::
2141
+
2142
+ sage: R.<x,zw> = QQ[]
2143
+ sage: S = magma(R) # optional - magma
2144
+ sage: S.gen_names() # optional - magma
2145
+ ('_sage_[...]', '_sage_[...]')
2146
+ sage: magma(S.gen_names()[1]) # optional - magma
2147
+ zw
2148
+ """
2149
+ try:
2150
+ return self.__gen_names
2151
+ except AttributeError:
2152
+ self.__gen_names = tuple([x.name() for x in self.gens()])
2153
+ return self.__gen_names
2154
+
2155
+ def evaluate(self, *args):
2156
+ r"""
2157
+ Evaluate ``self`` at the inputs.
2158
+
2159
+ INPUT:
2160
+
2161
+ - ``*args`` -- import arguments
2162
+
2163
+ OUTPUT: self(\*args)
2164
+
2165
+ EXAMPLES::
2166
+
2167
+ sage: # optional - magma
2168
+ sage: f = magma('Factorization')
2169
+ sage: f.evaluate(15)
2170
+ [ <3, 1>, <5, 1> ]
2171
+ sage: f(15)
2172
+ [ <3, 1>, <5, 1> ]
2173
+ sage: f = magma('GCD')
2174
+ sage: f.evaluate(15,20)
2175
+ 5
2176
+
2177
+ sage: m = matrix(QQ, 2, 2, [2,3,5,7]) # optional - magma
2178
+ sage: f = magma('ElementaryDivisors') # optional - magma
2179
+ sage: f.evaluate(m) # optional - magma
2180
+ [ 1, 1 ]
2181
+ """
2182
+ P = self._check_valid()
2183
+ names = ','.join(a._magma_init_(P) for a in args)
2184
+ return P('%s(%s)' % (self.name(), names))
2185
+
2186
+ eval = evaluate
2187
+
2188
+ def __call__(self, *args):
2189
+ """
2190
+ Coerce something into the object (using the Magma ! notation).
2191
+
2192
+ For function calls, use self.eval(...).
2193
+
2194
+ EXAMPLES::
2195
+
2196
+ sage: # optional - magma
2197
+ sage: M = magma.RMatrixSpace(magma.IntegerRing(), 2, 2)
2198
+ sage: A = M([1,2,3,4]); A
2199
+ [1 2]
2200
+ [3 4]
2201
+ sage: type(A)
2202
+ <class 'sage.interfaces.magma.MagmaElement'>
2203
+ sage: A.Type()
2204
+ ModMatRngElt
2205
+ """
2206
+ if len(args) > 1:
2207
+ return self.evaluate(*args)
2208
+ P = self._check_valid()
2209
+ x = P(args[0])
2210
+ try:
2211
+ return P('%s!%s' % (self.name(), x.name()))
2212
+ except (RuntimeError, TypeError):
2213
+ return self.evaluate(*args)
2214
+
2215
+ def __iter__(self):
2216
+ """
2217
+ Return iterator over this Magma element.
2218
+
2219
+ OUTPUT: generator object
2220
+
2221
+ .. warning::
2222
+
2223
+ Internally this constructs the list of elements in ``self`` in
2224
+ Magma, which is not a lazy operation. This is because Magma
2225
+ doesn't have a notion of lazy iterators, unfortunately.
2226
+
2227
+ EXAMPLES::
2228
+
2229
+ sage: # optional - magma
2230
+ sage: V = magma('VectorSpace(GF(3),2)')
2231
+ sage: V
2232
+ Full Vector space of degree 2 over GF(3)
2233
+ sage: w = V.__iter__(); w
2234
+ <generator object ...__iter__ at ...>
2235
+ sage: next(w)
2236
+ (0 0)
2237
+ sage: next(w)
2238
+ (1 0)
2239
+ sage: list(w)
2240
+ [(2 0), (0 1), (1 1), (2 1), (0 2), (1 2), (2 2)]
2241
+ """
2242
+ P = self._check_valid()
2243
+ z = P('[_a : _a in %s]' % self.name())
2244
+ for i in range(1, len(z) + 1):
2245
+ yield z[i]
2246
+
2247
+ def __len__(self):
2248
+ r"""
2249
+ Return cardinality of this Magma element.
2250
+
2251
+ This is the same as ``#self`` in Magma.
2252
+
2253
+ EXAMPLES::
2254
+
2255
+ sage: # optional - magma
2256
+ sage: V = magma('VectorSpace(GF(3),2)')
2257
+ sage: V
2258
+ Full Vector space of degree 2 over GF(3)
2259
+ sage: len(V)
2260
+ 9
2261
+ sage: V.__len__()
2262
+ 9
2263
+ """
2264
+ P = self._check_valid()
2265
+ return int(P.eval('#%s' % self.name()))
2266
+
2267
+ def _polynomial_(self, R):
2268
+ """
2269
+ Try to convert ``self`` into a polynomial in the univariate polynomial
2270
+ ring `R`.
2271
+
2272
+ EXAMPLES::
2273
+
2274
+ sage: R.<x> = QQ[]
2275
+ sage: f = magma(x^2 + 2/3*x + 5) # optional - magma
2276
+ sage: f # optional - magma
2277
+ x^2 + 2/3*x + 5
2278
+ sage: f.Type() # optional - magma
2279
+ RngUPolElt
2280
+ sage: f._polynomial_(R) # optional - magma
2281
+ x^2 + 2/3*x + 5
2282
+ """
2283
+ return R(list(self.Eltseq()))
2284
+
2285
+ def _latex_(self) -> str:
2286
+ r"""
2287
+ Return latex representation of ``self``.
2288
+
2289
+ AUTHORS:
2290
+
2291
+ - Jennifer Balakrishnan
2292
+
2293
+ Types that are nicely latexed include:
2294
+
2295
+ - rationals
2296
+
2297
+ - matrices
2298
+
2299
+ - polynomials
2300
+
2301
+ - binary quadratic forms
2302
+
2303
+ - elements of quadratic, cyclotomic number fields, and general
2304
+ number fields
2305
+
2306
+ - points
2307
+
2308
+ - elliptic curves
2309
+
2310
+ - power series
2311
+
2312
+ IMPLEMENTATION: Calls latex.m, which is in
2313
+ SAGE_EXTCODE/magma/latex.m
2314
+
2315
+ EXAMPLES::
2316
+
2317
+ sage: latex(magma('-2/3')) # optional - magma
2318
+ \frac{-2}{3}
2319
+ sage: magma('-2/3')._latex_() # optional - magma
2320
+ '\\frac{-2}{3}'
2321
+
2322
+ ::
2323
+
2324
+ sage: magma.eval('R<x> := PolynomialRing(RationalField()); f := (x-17/2)^3;') # optional - magma
2325
+ ''
2326
+ sage: latex(magma('f')) # optional - magma
2327
+ x^{3}-\frac{51}{2}x^{2}+\frac{867}{4}x-\frac{4913}{8}
2328
+
2329
+ ::
2330
+
2331
+ sage: latex(magma('(MatrixAlgebra(RationalField(),3)![0,2,3,4,5,6,7,8,9])^(-1)')) # optional - magma
2332
+ \left(\begin{array}{ccc}-1&2&-1\\2&-7&4\\-1&\frac{14}{3}&\frac{-8}{3}\end{array}\right)
2333
+
2334
+ ::
2335
+
2336
+ sage: magma.eval('K<a> := CyclotomicField(11)') # optional - magma
2337
+ ''
2338
+ sage: latex(magma('a^3 + a - 17/3')) # optional - magma
2339
+ \frac{-17}{3}+\zeta_{11}+\zeta_{11}^{3}
2340
+
2341
+ ::
2342
+
2343
+ sage: latex(magma('EllipticCurve([1,2/3,3/4,4/5,-5/6])')) # optional - magma
2344
+ y^2+xy+\frac{3}{4}y=x^3+\frac{2}{3}x^2+\frac{4}{5}x-\frac{5}{6}
2345
+
2346
+ ::
2347
+
2348
+ sage: _=magma.eval('R<x> := PolynomialRing(RationalField())') # optional - magma
2349
+ sage: _=magma.eval('K<a> := NumberField(x^3+17*x+2)') # optional - magma
2350
+ sage: latex(magma('(1/3)*a^2 - 17/3*a + 2')) # optional - magma
2351
+ 2-\frac{17}{3}a+\frac{1}{3}a^{2}
2352
+
2353
+ Sage auto-detects the greek letters and puts backslashes in::
2354
+
2355
+ sage: _=magma.eval('R<x> := PolynomialRing(RationalField())') # optional - magma
2356
+ sage: _=magma.eval('K<alpha> := NumberField(x^3+17*x+2)') # optional - magma
2357
+ sage: latex(magma('(1/3)*alpha^2 - 17/3*alpha + 2')) # optional - magma
2358
+ 2-\frac{17}{3}\alpha+\frac{1}{3}\alpha^{2}
2359
+
2360
+ ::
2361
+
2362
+ sage: _=magma.eval('R<alpha> := PolynomialRing(RationalField())') # optional - magma
2363
+ sage: latex(magma('alpha^3-1/7*alpha + 3')) # optional - magma
2364
+ \alpha^{3}-\frac{1}{7}\alpha+3
2365
+
2366
+ Finite field elements::
2367
+
2368
+ sage: _=magma.eval('K<a> := GF(27)') # optional - magma
2369
+ sage: latex(magma('a^2+2')) # optional - magma
2370
+ 2+a^{2}
2371
+
2372
+ Printing of unnamed (dollar sign) generators works correctly::
2373
+
2374
+ sage: latex(magma('FiniteField(81).1^2+1')) # optional - magma
2375
+ 1+\$.1^{2}
2376
+
2377
+ Finite fields::
2378
+
2379
+ sage: latex(magma('FiniteField(3)')) # optional - magma
2380
+ \mathbf{F}_{{3}}
2381
+ sage: latex(magma('FiniteField(27)')) # optional - magma
2382
+ \mathbf{F}_{{3}^{3}}
2383
+
2384
+ Power Series::
2385
+
2386
+ sage: # optional - magma
2387
+ sage: _=magma.eval('R<x> := PowerSeriesRing(RationalField())')
2388
+ sage: latex(magma('(1/(1+x))'))
2389
+ 1-x+x^{2}-x^{3}+x^{4}-x^{5}+x^{6}-x^{7}+x^{8}-x^{9}+x^{10}-x^{11}+x^{12}-x^{13}+x^{14}-x^{15}+x^{16}-x^{17}+x^{18}-x^{19}+O(x^{20})
2390
+ sage: _=magma.eval('R<x> := PowerSeriesRing(RationalField())')
2391
+ sage: latex(magma('(-1/(2+x + O(x^3)))'))
2392
+ \frac{-1}{2}+\frac{1}{4}x-\frac{1}{8}x^{2}+O(x^{3})
2393
+
2394
+ `p`-adic Numbers::
2395
+
2396
+ sage: latex(magma('pAdicField(7,4)!9333294394/49')) # optional - magma
2397
+ 4\cdot{}7^{-2} + 5\cdot{}7^{-1} + 5+ 6\cdot{}7^{1} + O(7^{2})
2398
+ """
2399
+ P = self._check_valid()
2400
+ s = str(P.eval('Latex(%s)' % self.name()))
2401
+ v = '\\mathrm{'
2402
+ if s[:len(v)] == v:
2403
+ raise AttributeError
2404
+ return s
2405
+
2406
+ def set_magma_attribute(self, attrname, value):
2407
+ """
2408
+ INPUT:
2409
+
2410
+ - ``attrname`` -- string
2411
+ - ``value`` -- something coercible to a MagmaElement
2412
+
2413
+ EXAMPLES::
2414
+
2415
+ sage: # optional - magma
2416
+ sage: V = magma("VectorSpace(RationalField(),2)")
2417
+ sage: V.set_magma_attribute('M',10)
2418
+ sage: V.get_magma_attribute('M')
2419
+ 10
2420
+ sage: V.M
2421
+ 10
2422
+ """
2423
+ P = self.parent() # instance of Magma that contains this element.
2424
+ if not (isinstance(value, MagmaElement) and value.parent() is P):
2425
+ value = P(value)
2426
+ P.eval('%s`%s := %s' % (self.name(), attrname, value.name()))
2427
+
2428
+ def get_magma_attribute(self, attrname):
2429
+ """
2430
+ Return value of a given Magma attribute. This is like selfattrname
2431
+ in Magma.
2432
+
2433
+ OUTPUT: :class:`MagmaElement`
2434
+
2435
+ EXAMPLES::
2436
+
2437
+ sage: # optional - magma
2438
+ sage: V = magma("VectorSpace(RationalField(),10)")
2439
+ sage: V.set_magma_attribute('M','"hello"')
2440
+ sage: V.get_magma_attribute('M')
2441
+ hello
2442
+ sage: V.M
2443
+ hello
2444
+ """
2445
+ P = self.parent()
2446
+ return P('%s`%s' % (self.name(), attrname))
2447
+
2448
+ def list_attributes(self):
2449
+ """
2450
+ Return the attributes of self, obtained by calling the
2451
+ ListAttributes function in Magma.
2452
+
2453
+ OUTPUT: list of strings
2454
+
2455
+ EXAMPLES: We observe that vector spaces in Magma have numerous
2456
+ funny and mysterious attributes. ::
2457
+
2458
+ sage: V = magma("VectorSpace(RationalField(),2)") # optional - magma
2459
+ sage: v = V.list_attributes(); v.sort() # optional - magma
2460
+ sage: print(v) # optional - magma
2461
+ ['Coroots', 'Involution', ..., 'p', 'ssbasis', 'weights']
2462
+ """
2463
+ return magma.eval('ListAttributes(Type(%s))' % self.name()).split()
2464
+
2465
+ def _tab_completion(self):
2466
+ """
2467
+ Return all Magma functions that have this Magma element as first
2468
+ input. This is used for tab completion.
2469
+
2470
+ .. NOTE::
2471
+
2472
+ This function can unfortunately be slow if there are a very
2473
+ large number of functions, e.g., when ``self`` is an
2474
+ integer. (This could be fixed by the addition of an
2475
+ appropriate function to the Magma kernel, which is
2476
+ something that can only be done by the Magma developers.)
2477
+
2478
+ OUTPUT:
2479
+
2480
+ - ``list`` -- sorted list of distinct strings
2481
+
2482
+ EXAMPLES::
2483
+
2484
+ sage: R.<x> = ZZ[] # optional - magma
2485
+ sage: v = magma(R)._tab_completion() # optional - magma
2486
+ sage: v # optional - magma
2487
+ ["'*'", "'+'", "'.'", "'/'", "'eq'", "'meet'", "'subset'", ...]
2488
+ """
2489
+ M = self.methods()
2490
+ N = []
2491
+ for x in M:
2492
+ i = x.find('(')
2493
+ N.append(x[:i])
2494
+ v = sorted(set(N + self.list_attributes()))
2495
+ return v
2496
+
2497
+ def methods(self, any=False):
2498
+ """
2499
+ Return signatures of all Magma intrinsics that can take ``self`` as the
2500
+ first argument, as strings.
2501
+
2502
+ INPUT:
2503
+
2504
+ - ``any`` -- boolean (default: ``False``); if ``True``, also
2505
+ include signatures with Any as first argument
2506
+
2507
+ OUTPUT: list of strings
2508
+
2509
+ EXAMPLES::
2510
+
2511
+ sage: v = magma('2/3').methods() # optional - magma
2512
+ sage: v[0] # optional - magma
2513
+ "'*'..."
2514
+ """
2515
+ t = str(self.Type())
2516
+ X = self.parent().eval('ListSignatures(%s)' % self.Type()).split('\n')
2517
+ X = X[2:] # because the first 2 lines are not relevant
2518
+ t0 = t + ',' # t as first argument among several
2519
+ t1 = t + ')' # t as only argument
2520
+ result = []
2521
+ for x in X:
2522
+ x1 = x.split('::')[1] # typical line starts (f::Elt, g::Elt)
2523
+ if x1.startswith(t0) or x1.startswith(t1):
2524
+ result.append(x)
2525
+ elif any and x1.startswith("Any"):
2526
+ result.append(x)
2527
+ return result
2528
+
2529
+ def __floordiv__(self, x):
2530
+ """
2531
+ Quotient of division of ``self`` by ``other``. This is denoted ``//``
2532
+ (``div`` in magma).
2533
+
2534
+ EXAMPLES::
2535
+
2536
+ sage: R.<x,y,z> = QQ[]
2537
+ sage: magma(5)//magma(2) # optional - magma
2538
+ 2
2539
+ sage: m = magma(x*z + x*y) # optional - magma
2540
+ sage: n = magma(x) # optional - magma
2541
+ sage: m//n # optional - magma
2542
+ y + z
2543
+ """
2544
+ return self.parent()('%s div %s' % (self.name(), x.name()))
2545
+
2546
+ def __bool__(self):
2547
+ """
2548
+ Return ``True`` if ``self`` is nonzero according to Magma.
2549
+
2550
+ If Magma cannot decide, i.e., is raising an error
2551
+ then also return ``True``.
2552
+
2553
+ EXAMPLES: We define a Magma vector space::
2554
+
2555
+ sage: V = magma('VectorSpace(GF(3),2)'); V # optional - magma
2556
+ Full Vector space of degree 2 over GF(3)
2557
+
2558
+ The first generator is nonzero::
2559
+
2560
+ sage: bool(V.gen(1)) # optional - magma
2561
+ True
2562
+
2563
+ The zero element is zero::
2564
+
2565
+ sage: bool(V(0)) # optional - magma
2566
+ False
2567
+
2568
+ The space itself is nonzero (the default - in Magma no comparison
2569
+ to 0 is possible)::
2570
+
2571
+ sage: bool(V) # optional - magma
2572
+ True
2573
+
2574
+ Note that ``bool`` calls ``__bool__`` in Python 3.
2575
+
2576
+ Test use in bool conversions of bools::
2577
+
2578
+ sage: # optional - magma
2579
+ sage: bool(magma(False))
2580
+ False
2581
+ sage: bool(magma(True))
2582
+ True
2583
+ sage: bool(magma(1))
2584
+ True
2585
+ sage: bool(magma(0))
2586
+ False
2587
+
2588
+ TESTS:
2589
+
2590
+ Verify that :issue:`32602` is fixed::
2591
+
2592
+ sage: magma("1 eq 0").bool() # optional - magma
2593
+ False
2594
+ sage: magma("1 eq 1").bool() # optional - magma
2595
+ True
2596
+ sage: Q.<x> = PolynomialRing(GF(3))
2597
+ sage: u = x^6+x^4+2*x^3+2*x+1
2598
+ sage: F0 = magma.FunctionField(GF(3)) # optional - magma
2599
+ sage: bool(F0.1) # optional - magma
2600
+ True
2601
+ """
2602
+ try:
2603
+ return str(self.parent()("%s eq 0" % self.name())) == "false"
2604
+ except TypeError:
2605
+ # comparing with 0 didn't work; try comparing with false
2606
+ try:
2607
+ return str(self.parent()("%s eq false" % self.name())) == "false"
2608
+ except TypeError:
2609
+ pass
2610
+ return True
2611
+
2612
+ def sub(self, gens):
2613
+ """
2614
+ Return the sub-object of ``self`` with given gens.
2615
+
2616
+ INPUT:
2617
+
2618
+ - ``gens`` -- object or list/tuple of generators
2619
+
2620
+ EXAMPLES::
2621
+
2622
+ sage: V = magma('VectorSpace(RationalField(),3)') # optional - magma
2623
+ sage: W = V.sub([ [1,2,3], [1,1,2] ]); W # optional - magma
2624
+ Vector space of degree 3, dimension 2 over Rational Field
2625
+ Generators:
2626
+ (1 2 3)
2627
+ (1 1 2)
2628
+ Echelonized basis:
2629
+ (1 0 1)
2630
+ (0 1 1)
2631
+ """
2632
+ return self.parent().bar_call(self, 'sub', gens)
2633
+
2634
+ def quo(self, gens, **args):
2635
+ """
2636
+ Return the quotient of ``self`` by the given object or list of
2637
+ generators.
2638
+
2639
+ INPUT:
2640
+
2641
+ - ``gens`` -- object or list/tuple of generators
2642
+ - further named arguments that are ignored
2643
+
2644
+ OUTPUT:
2645
+
2646
+ - ``magma element`` -- the quotient object
2647
+
2648
+ - ``magma element`` -- mapping from ``self`` to the
2649
+ quotient object
2650
+
2651
+ EXAMPLES::
2652
+
2653
+ sage: V = magma('VectorSpace(RationalField(),3)') # optional - magma
2654
+ sage: V.quo([[1,2,3], [1,1,2]]) # optional - magma
2655
+ (Full Vector space of degree 1 over Rational Field, Mapping from: Full Vector space of degree 3 over Rational Field to Full Vector space of degree 1 over Rational Field)
2656
+
2657
+ We illustrate quotienting out by an object instead of a list of
2658
+ generators::
2659
+
2660
+ sage: W = V.sub([ [1,2,3], [1,1,2] ]) # optional - magma
2661
+ sage: V.quo(W) # optional - magma
2662
+ (Full Vector space of degree 1 over Rational Field, Mapping from: Full Vector space of degree 3 over Rational Field to Full Vector space of degree 1 over Rational Field)
2663
+
2664
+ We quotient a ZZ module out by a submodule.
2665
+
2666
+ ::
2667
+
2668
+ sage: # optional - magma
2669
+ sage: V = magma.RModule(ZZ,3); V
2670
+ RModule(IntegerRing(), 3)
2671
+ sage: W, phi = V.quo([[1,2,3]])
2672
+ sage: W
2673
+ RModule(IntegerRing(), 2)
2674
+ sage: phi
2675
+ Mapping from: RModule(IntegerRing(), 3) to RModule(IntegerRing(), 2)
2676
+ """
2677
+ return self.parent().bar_call(self, 'quo', gens, nvals=2)
2678
+
2679
+ def ideal(self, gens):
2680
+ """
2681
+ Return the ideal of ``self`` with given list of generators.
2682
+
2683
+ INPUT:
2684
+
2685
+ - ``gens`` -- object or list/tuple of generators
2686
+
2687
+ OUTPUT:
2688
+
2689
+ - ``magma element`` -- a Magma ideal
2690
+
2691
+ EXAMPLES::
2692
+
2693
+ sage: # optional - magma
2694
+ sage: R = magma('PolynomialRing(RationalField())')
2695
+ sage: R.assign_names(['x'])
2696
+ sage: x = R.1
2697
+ sage: R.ideal([x^2 - 1, x^3 - 1])
2698
+ Ideal of Univariate Polynomial Ring in x over Rational Field generated by x - 1
2699
+ """
2700
+ return self.parent().bar_call(self, 'ideal', gens, nvals=1)
2701
+
2702
+
2703
+ magma = Magma()
2704
+
2705
+
2706
+ def reduce_load_Magma():
2707
+ """
2708
+ Used in unpickling a Magma interface.
2709
+
2710
+ This functions just returns the global default Magma interface.
2711
+
2712
+ EXAMPLES::
2713
+
2714
+ sage: sage.interfaces.magma.reduce_load_Magma()
2715
+ Magma
2716
+ """
2717
+ return magma
2718
+
2719
+
2720
+ def magma_console():
2721
+ """
2722
+ Run a command line Magma session.
2723
+
2724
+ EXAMPLES::
2725
+
2726
+ sage: magma_console() # not tested
2727
+ Magma V2.14-9 Sat Oct 11 2008 06:36:41 on one [Seed = 1157408761]
2728
+ Type ? for help. Type <Ctrl>-D to quit.
2729
+ >
2730
+ Total time: 2.820 seconds, Total memory usage: 3.95MB
2731
+ """
2732
+ from sage.repl.rich_output.display_manager import get_display_manager
2733
+ if not get_display_manager().is_in_terminal():
2734
+ raise RuntimeError('Can use the console only in the terminal. Try %%magma magics instead.')
2735
+ os.system('magma')
2736
+
2737
+
2738
+ class MagmaGBLogPrettyPrinter:
2739
+ """
2740
+ A device which filters Magma Groebner basis computation logs.
2741
+ """
2742
+ cmd_inpt = re.compile("^>>>$")
2743
+ app_inpt = re.compile("^Append\\(~_sage_, 0\\);$")
2744
+
2745
+ deg_curr = re.compile(
2746
+ "^Basis length\\: (\\d+), queue length\\: (\\d+), step degree\\: (\\d+), num pairs\\: (\\d+)$"
2747
+ )
2748
+ pol_curr = re.compile("^Number of pair polynomials\\: (\\d+), at (\\d+) column\\(s\\), .*")
2749
+
2750
+ def __init__(self, verbosity=1, style='magma'):
2751
+ """
2752
+ Construct a new Magma Groebner Basis log pretty printer.
2753
+
2754
+ INPUT:
2755
+
2756
+ - ``verbosity`` -- how much information should be printed
2757
+ (between 0 and 1)
2758
+
2759
+ - ``style`` -- if "magma" the full Magma log is printed; if
2760
+ 'sage' only the current degree and the number of pairs in
2761
+ the queue is printed (default: ``'magma'``).
2762
+
2763
+ EXAMPLES::
2764
+
2765
+ sage: # needs sage.libs.singular
2766
+ sage: P.<x,y,z> = GF(32003)[]
2767
+ sage: I = sage.rings.ideal.Cyclic(P)
2768
+ sage: _ = I.groebner_basis('magma',prot='sage') # indirect doctest, optional - magma, not tested
2769
+
2770
+ Leading term degree: 2. Critical pairs: 2.
2771
+ Leading term degree: 3. Critical pairs: 1.
2772
+
2773
+ Highest degree reached during computation: 3.
2774
+
2775
+ sage: # needs sage.libs.singular
2776
+ sage: P.<x,y,z> = GF(32003)[]
2777
+ sage: I = sage.rings.ideal.Cyclic(P)
2778
+ sage: _ = I.groebner_basis('magma',prot=True) # indirect doctest, optional - magma, not tested
2779
+ ********************
2780
+ FAUGERE F4 ALGORITHM
2781
+ ********************
2782
+ Coefficient ring: GF(32003)
2783
+ Rank: 3
2784
+ Order: Graded Reverse Lexicographical
2785
+ NEW hash table
2786
+ Matrix kind: Modular FP
2787
+ Datum size: 4
2788
+ No queue sort
2789
+ Initial length: 3
2790
+ Inhomogeneous
2791
+
2792
+ Initial queue setup time: 0.000
2793
+ Initial queue length: 2
2794
+
2795
+ *******
2796
+ STEP 1
2797
+ Basis length: 3, queue length: 2, step degree: 2, num pairs: 1
2798
+ Basis total mons: 8, average length: 2.667
2799
+ Number of pair polynomials: 1, at 4 column(s), 0.000
2800
+ ...
2801
+ Total Faugere F4 time: 0.000, real time: 0.000
2802
+
2803
+ sage: # needs sage.libs.pari
2804
+ sage: set_random_seed(1)
2805
+ sage: sr = mq.SR(1,1,2,4)
2806
+ sage: F,s = sr.polynomial_system()
2807
+ sage: I = F.ideal()
2808
+ sage: _ = I.groebner_basis('magma',prot='sage') # indirect doctest, optional - magma, not tested
2809
+ Leading term degree: 1. Critical pairs: 40.
2810
+ Leading term degree: 2. Critical pairs: 40.
2811
+ Leading term degree: 3. Critical pairs: 38.
2812
+ Leading term degree: 2. Critical pairs: 327.
2813
+ Leading term degree: 2. Critical pairs: 450.
2814
+ Leading term degree: 2. Critical pairs: 416.
2815
+ Leading term degree: 3. Critical pairs: 415.
2816
+ Leading term degree: 4. Critical pairs: 98 (all pairs of current degree eliminated by criteria).
2817
+ Leading term degree: 5. Critical pairs: 3 (all pairs of current degree eliminated by criteria).
2818
+
2819
+ Highest degree reached during computation: 3.
2820
+ """
2821
+ self.verbosity = verbosity
2822
+ if style not in ['sage', 'magma']:
2823
+ raise ValueError('style must be sage or magma')
2824
+ self.style = style
2825
+
2826
+ self.curr_deg = 0 # current degree
2827
+ self.curr_npairs = 0 # current number of pairs to be considered
2828
+ self.max_deg = 0 # maximal degree in total
2829
+
2830
+ self.storage = "" # stores incomplete strings
2831
+ self.sync = None # should we expect a sync integer?
2832
+
2833
+ def write(self, s):
2834
+ """
2835
+ EXAMPLES::
2836
+
2837
+ sage: # needs sage.libs.singular
2838
+ sage: P.<x,y,z> = GF(32003)[]
2839
+ sage: I = sage.rings.ideal.Katsura(P)
2840
+ sage: _ = I.groebner_basis('magma',prot=True) # indirect doctest, optional - magma
2841
+ ...
2842
+ ********************
2843
+ FAUGERE F4 ALGORITHM
2844
+ ********************
2845
+ ...
2846
+ Total Faugere F4 time: ..., real time: ...
2847
+ """
2848
+ verbosity, style = self.verbosity, self.style
2849
+
2850
+ if isinstance(s, bytes):
2851
+ # sys.stdout.encoding can be None or something else
2852
+ if isinstance(sys.stdout.encoding, str):
2853
+ s = s.decode(sys.stdout.encoding)
2854
+ else:
2855
+ s = s.decode("UTF-8")
2856
+
2857
+ if self.storage:
2858
+ s = self.storage + s
2859
+ self.storage = ""
2860
+
2861
+ for line in s.splitlines():
2862
+ # deal with the Sage <-> Magma syncing code
2863
+ match = re.match(MagmaGBLogPrettyPrinter.cmd_inpt, line)
2864
+ if match:
2865
+ self.sync = 1
2866
+ continue
2867
+
2868
+ if self.sync:
2869
+ if self.sync == 1:
2870
+ self.sync = line
2871
+ continue
2872
+ else:
2873
+ if line == '':
2874
+ continue
2875
+ self.sync = None
2876
+ continue
2877
+
2878
+ if re.match(MagmaGBLogPrettyPrinter.app_inpt, line):
2879
+ continue
2880
+
2881
+ if re.match(MagmaGBLogPrettyPrinter.deg_curr, line):
2882
+ match = re.match(MagmaGBLogPrettyPrinter.deg_curr, line)
2883
+
2884
+ nbasis, npairs, deg, npairs_deg = map(int, match.groups())
2885
+
2886
+ self.curr_deg = deg
2887
+ self.curr_npairs = npairs
2888
+
2889
+ if re.match(MagmaGBLogPrettyPrinter.pol_curr, line):
2890
+ match = re.match(MagmaGBLogPrettyPrinter.pol_curr, line)
2891
+ pol_curr, col_curr = map(int, match.groups())
2892
+
2893
+ if pol_curr != 0:
2894
+ self.max_deg = max(self.max_deg, self.curr_deg)
2895
+
2896
+ if style == "sage" and verbosity >= 1:
2897
+ print("Leading term degree: %2d. Critical pairs: %d." %
2898
+ (self.curr_deg, self.curr_npairs))
2899
+ else:
2900
+ if style == "sage" and verbosity >= 1:
2901
+ print("Leading term degree: %2d. Critical pairs: %d (all pairs of current degree eliminated by criteria)." %
2902
+ (self.curr_deg, self.curr_npairs))
2903
+
2904
+ if style == "magma" and verbosity >= 1:
2905
+ print(line)
2906
+
2907
+ def flush(self):
2908
+ """
2909
+ EXAMPLES::
2910
+
2911
+ sage: from sage.interfaces.magma import MagmaGBLogPrettyPrinter
2912
+ sage: logs = MagmaGBLogPrettyPrinter()
2913
+ sage: logs.flush()
2914
+ """
2915
+ import sys
2916
+ sys.stdout.flush()
2917
+
2918
+
2919
+ class MagmaGBDefaultContext:
2920
+ """
2921
+ Context to force preservation of verbosity options for Magma's
2922
+ Groebner basis computation.
2923
+ """
2924
+ def __init__(self, magma=None):
2925
+ """
2926
+ INPUT:
2927
+
2928
+ - ``magma`` -- (default: ``magma_default``)
2929
+
2930
+ EXAMPLES::
2931
+
2932
+ sage: from sage.interfaces.magma import MagmaGBDefaultContext
2933
+ sage: magma.SetVerbose('Groebner',1) # optional - magma
2934
+ sage: with MagmaGBDefaultContext(): magma.GetVerbose('Groebner') # optional - magma
2935
+ 0
2936
+ """
2937
+ if magma is None:
2938
+ from sage.interfaces.magma import magma as magma_default
2939
+ magma = magma_default
2940
+
2941
+ self.magma = magma
2942
+
2943
+ def __enter__(self):
2944
+ """
2945
+ EXAMPLES::
2946
+
2947
+ sage: from sage.interfaces.magma import MagmaGBDefaultContext
2948
+ sage: magma.SetVerbose('Groebner',1) # optional - magma
2949
+ sage: with MagmaGBDefaultContext(): magma.GetVerbose('Groebner') # optional - magma
2950
+ 0
2951
+ """
2952
+ self.groebner_basis_verbose = self.magma.GetVerbose('Groebner')
2953
+ self.magma.SetVerbose('Groebner', 0)
2954
+
2955
+ def __exit__(self, typ, value, tb):
2956
+ """
2957
+ EXAMPLES::
2958
+
2959
+ sage: from sage.interfaces.magma import MagmaGBDefaultContext
2960
+ sage: magma.SetVerbose('Groebner',1) # optional - magma
2961
+ sage: with MagmaGBDefaultContext(): magma.GetVerbose('Groebner') # optional - magma
2962
+ 0
2963
+ sage: magma.GetVerbose('Groebner') # optional - magma
2964
+ 1
2965
+ """
2966
+ self.magma.SetVerbose('Groebner', self.groebner_basis_verbose)
2967
+
2968
+
2969
+ def magma_gb_standard_options(func):
2970
+ """
2971
+ Decorator to force default options for Magma.
2972
+
2973
+ EXAMPLES::
2974
+
2975
+ sage: # needs sage.libs.singular
2976
+ sage: P.<a,b,c,d,e> = PolynomialRing(GF(127))
2977
+ sage: J = sage.rings.ideal.Cyclic(P).homogenize()
2978
+ sage: from sage.misc.sageinspect import sage_getsource
2979
+ sage: "mself" in sage_getsource(J._groebner_basis_magma)
2980
+ True
2981
+ """
2982
+ from sage.misc.decorators import sage_wraps
2983
+
2984
+ @sage_wraps(func)
2985
+ def wrapper(*args, **kwds):
2986
+ """
2987
+ Execute function in ``MagmaGBDefaultContext``.
2988
+ """
2989
+ with MagmaGBDefaultContext():
2990
+ return func(*args, **kwds)
2991
+ return wrapper