diff --git a/src/sage/interfaces/macaulay2.py b/src/sage/interfaces/macaulay2.py index 98182d379c6..e28ac97fb5f 100644 --- a/src/sage/interfaces/macaulay2.py +++ b/src/sage/interfaces/macaulay2.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - macaulay2 r""" Interface to Macaulay2 @@ -27,7 +28,6 @@ EXAMPLES:: - sage: # optional - macaulay2 sage: macaulay2('3/5 + 7/11') 68 -- @@ -38,7 +38,6 @@ sage: f(5) 125 - sage: # optional - macaulay2 sage: R = macaulay2('ZZ/5[x,y,z]') sage: R ZZ @@ -56,12 +55,10 @@ can be passed as an argument. This is useful for types like polynomial rings which acquire that name in Macaulay2:: - sage: # optional - macaulay2 sage: R = macaulay2('QQ[x,y,z,w]', 'R') sage: R R - sage: # optional - macaulay2 sage: f = macaulay2('x^4 + 2*x*y^3 + x*y^2*w + x*y*z*w + x*y*w^2' ....: '+ 2*x*z*w^2 + y^4 + y^3*w + 2*y^2*z*w + z^4 + w^4') sage: f @@ -75,16 +72,15 @@ Use :meth:`eval` for explicit control over what is sent to the interpreter. The argument is evaluated in Macaulay2 as is:: - sage: # optional - macaulay2 sage: macaulay2.eval('compactMatrixForm') true sage: macaulay2.eval('compactMatrixForm = false;') sage: macaulay2.eval('matrix {{1, x^2+y}}') - | 2 | - | 1 x + y | + | 2 | + | 1 x + y | - 1 2 - Matrix R <--- R + 1 2 + Matrix R <-- R sage: macaulay2.eval('compactMatrixForm = true;') @@ -121,9 +117,9 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** - import os import re +from typing import Iterator import sage.interfaces.abc from sage.interfaces.expect import ( @@ -170,11 +166,12 @@ def remove_output_labels(s) -> str: """ label = re.compile(r"^o+[0-9]+ (=|:) |^ *") lines = s.split("\n") - matches = [label.match(l) for l in lines if l] + it = (label.match(li) for li in lines if li) + matches = [m for m in it if m is not None] if not matches: return s n = min(m.end() - m.start() for m in matches) - return "\n".join(l[n:] for l in lines) + return "\n".join(li[n:] for li in lines) PROMPT = "_EGAS_ : " @@ -186,7 +183,8 @@ class Macaulay2(ExtraTabCompletion, Expect): Interface to the Macaulay2 interpreter. """ def __init__(self, maxread=None, script_subdirectory=None, - logfile=None, server=None, server_tmpdir=None, command=None): + logfile=None, server=None, + server_tmpdir=None, command=None) -> None: """ Initialize a Macaulay2 interface instance. @@ -250,9 +248,9 @@ def __reduce__(self): sage: rlm2(*t) Macaulay2 """ - return reduce_load_macaulay2, tuple([]) + return reduce_load_macaulay2, tuple() - def _read_in_file_command(self, filename): + def _read_in_file_command(self, filename) -> str: """ Load and *execute* the content of ``filename`` in Macaulay2. @@ -273,38 +271,37 @@ def _read_in_file_command(self, filename): sage: f = open(filename, "w") sage: _ = f.write("sage_test = 7;") sage: f.close() - sage: macaulay2.read(filename) # indirect doctest, optional - macaulay2 - sage: macaulay2.eval("sage_test") # optional - macaulay2 + sage: macaulay2.read(filename) # indirect doctest + sage: macaulay2.eval("sage_test") 7 sage: import os sage: os.unlink(filename) - sage: macaulay2(10^10000) == 10^10000 # optional - macaulay2 + sage: macaulay2(10^10000) == 10^10000 True """ # We use `input` because `load` does not echo the output values return 'sageLoadMode=true;input "%s";sageLoadMode=false;' % filename - def _post_process_from_file(self, s): + def _post_process_from_file(self, s) -> str: r""" TESTS: Check that evaluating using a file gives the same result as without (:issue:`25903`):: sage: from sage.interfaces.macaulay2 import remove_output_labels - sage: s1 = macaulay2._eval_line_using_file('ZZ^2') # indirect doctest, optional - macaulay2 - sage: s2 = macaulay2._eval_line('ZZ^2', allow_use_file=False) # optional - macaulay2 - sage: remove_output_labels(s1) == remove_output_labels(s2) # optional - macaulay2 + sage: s1 = macaulay2._eval_line_using_file('ZZ^2') # indirect doctest + sage: s2 = macaulay2._eval_line('ZZ^2', allow_use_file=False) + sage: remove_output_labels(s1) == remove_output_labels(s2) True Test multiline input from file:: - sage: (macaulay2.eval('ZZ^2\nZZ^3', allow_use_file=False) == # indirect doctest, optional - macaulay2 + sage: (macaulay2.eval('ZZ^2\nZZ^3', allow_use_file=False) == # indirect doctest ....: macaulay2.eval('ZZ^2\n%sZZ^3' % (' ' * macaulay2._eval_using_file_cutoff))) True """ - s = '\n'.join(line for line in s.split('\n') - if not line.startswith(PROMPT_LOAD)) - return s + return '\n'.join(line for line in s.split('\n') + if not line.startswith(PROMPT_LOAD)) def eval(self, code, strip=True, **kwds): """ @@ -318,7 +315,7 @@ def eval(self, code, strip=True, **kwds): EXAMPLES:: - sage: macaulay2.eval("2+2") # optional - macaulay2 + sage: macaulay2.eval("2+2") 4 """ code = code.strip() @@ -328,13 +325,13 @@ def eval(self, code, strip=True, **kwds): ans = remove_output_labels(ans) return AsciiArtString(ans) - def restart(self): + def restart(self) -> None: r""" Restart Macaulay2 interpreter. TESTS:: - sage: macaulay2.restart() # optional - macaulay2 + sage: macaulay2.restart() """ # If we allow restart to be called as a function, there will be # parasitic output @@ -353,10 +350,10 @@ def set_seed(self, seed=None): EXAMPLES:: - sage: m = Macaulay2() # optional - macaulay2 - sage: m.set_seed(123456) # optional - macaulay2 + sage: m = Macaulay2() + sage: m.set_seed(123456) 123456 - sage: [m.random(100) for _ in range(11)] # optional - macaulay2 + sage: [m.random(100) for _ in range(11)] [8, 29, 5, 22, 4, 32, 35, 57, 3, 95, 36] """ if seed is None: @@ -373,14 +370,13 @@ class options(GlobalOptions): EXAMPLES:: - sage: # optional - macaulay2 sage: macaulay2.options.after_print = True sage: A = macaulay2(matrix([[1, 2], [3, 6]])); A | 1 2 | | 3 6 | - 2 2 - Matrix ZZ <--- ZZ + 2 2 + Matrix ZZ <-- ZZ sage: A.kernel() image | 2 | | -1 | @@ -409,16 +405,16 @@ def get(self, var): EXAMPLES:: - sage: macaulay2.set("a", "2") # optional - macaulay2 - sage: macaulay2.get("a") # optional - macaulay2 + sage: macaulay2.set("a", "2") + sage: macaulay2.get("a") 2 Note that the following syntax is used to obtain a ``Macaulay2Element`` instead:: - sage: a = macaulay2('2'); a # optional - macaulay2 + sage: a = macaulay2('2'); a 2 - sage: type(a) # optional - macaulay2 + sage: type(a) """ return self.eval('print(%s)' % var, strip=False) @@ -434,8 +430,8 @@ def set(self, var, value): EXAMPLES:: - sage: macaulay2.set("a", "1+1") # optional - macaulay2 - sage: macaulay2.get("a") # optional - macaulay2 + sage: macaulay2.set("a", "1+1") + sage: macaulay2.get("a") 2 TESTS: @@ -443,7 +439,6 @@ def set(self, var, value): Check that internal expect variables do not acquire their global variable name and that ``use`` is invoked (:issue:`28303`):: - sage: # optional - macaulay2 sage: R = macaulay2('QQ[x, y]') # indirect doctest sage: R.net() QQ[x...y] @@ -459,7 +454,7 @@ def set(self, var, value): if ans.find("stdio:") != -1: raise RuntimeError("Error evaluating Macaulay2 code.\nIN:%s\nOUT:%s" % (cmd, ans)) - def clear(self, var): + def clear(self, var) -> None: """ Clear the variable named ``var``. @@ -468,7 +463,6 @@ def clear(self, var): EXAMPLES:: - sage: # optional - macaulay2 sage: macaulay2.eval('R = QQ[x,y];') sage: macaulay2.eval('net class R') PolynomialRing @@ -480,7 +474,7 @@ def clear(self, var): Check that only internal variables get reused by the interface:: - sage: all(s.startswith('sage') for s in macaulay2._available_vars) # optional - macaulay2 + sage: all(s.startswith('sage') for s in macaulay2._available_vars) True """ if re.match(r'sage\d+$', var): @@ -490,11 +484,10 @@ def clear(self, var): cmd = 'globalAssign(symbol {0},symbol {0});'.format(var) Expect.eval(self, cmd, strip=False) - def _contains(self, v1, v2): + def _contains(self, v1, v2) -> bool: """ EXAMPLES:: - sage: # optional - macaulay2 sage: a = macaulay2([3,4,5]) sage: 0 in a, 2 in a, 3 in a (True, True, False) @@ -550,7 +543,7 @@ def console(self): """ macaulay2_console() - def _install_hints(self): + def _install_hints(self) -> str: r""" TESTS:: @@ -584,7 +577,7 @@ def _install_hints(self): or by setting the environment variable SAGE_MACAULAY2_COMMAND. """ - def _left_list_delim(self): + def _left_list_delim(self) -> str: """ Return the Macaulay2 left delimiter for lists. @@ -595,7 +588,7 @@ def _left_list_delim(self): """ return '{' - def _right_list_delim(self): + def _right_list_delim(self) -> str: """ Return the Macaulay2 right delimiter for lists. @@ -606,7 +599,7 @@ def _right_list_delim(self): """ return '}' - def _true_symbol(self): + def _true_symbol(self) -> str: """ Return the Macaulay2 symbol for True. @@ -617,7 +610,7 @@ def _true_symbol(self): """ return 'true' - def _false_symbol(self): + def _false_symbol(self) -> str: """ Return the Macaulay2 symbol for False. @@ -628,7 +621,7 @@ def _false_symbol(self): """ return 'false' - def _equality_symbol(self): + def _equality_symbol(self) -> str: """ Return the Macaulay2 symbol for equality. @@ -639,11 +632,10 @@ def _equality_symbol(self): """ return '==' - def cputime(self, t=None): + def cputime(self, t=None) -> float: """ EXAMPLES:: - sage: # optional - macaulay2 sage: R = macaulay2("QQ[x,y]") sage: x,y = R.gens() sage: a = (x+y+1)^20 @@ -651,18 +643,15 @@ def cputime(self, t=None): 0.48393700000000001 """ _t = float(self.cpuTime()._sage_()) - if t: - return _t - t - else: - return _t + return _t - t if t else _t - def version(self): + def version(self) -> tuple[int, ...]: """ Return the version of Macaulay2 as a tuple. EXAMPLES:: - sage: macaulay2.version() # optional - macaulay2 + sage: macaulay2.version() (1, ...) """ s = self.eval('version#"VERSION"') @@ -683,12 +672,12 @@ def ideal(self, *gens): EXAMPLES:: - sage: R2 = macaulay2.ring('QQ', '[x, y]'); R2 # optional - macaulay2 + sage: R2 = macaulay2.ring('QQ', '[x, y]'); R2 QQ[x...y] - sage: I = macaulay2.ideal( ('y^2 - x^3', 'x - y') ); I # optional - macaulay2 + sage: I = macaulay2.ideal( ('y^2 - x^3', 'x - y') ); I 3 2 ideal (- x + y , x - y) - sage: J = I^3; J.gb().gens().transpose() # optional - macaulay2 + sage: J = I^3; J.gb().gens().transpose() {-9} | y9-3y8+3y7-y6 | {-7} | xy6-2xy5+xy4-y7+2y6-y5 | {-5} | x2y3-x2y2-2xy4+2xy3+y5-y4 | @@ -721,30 +710,26 @@ def ring(self, base_ring='ZZ', vars='[x]', order='Lex'): This is a ring in variables named ``a`` through ``d`` over the finite field of order 7, with graded reverse lex ordering:: - sage: R1 = macaulay2.ring('ZZ/7', '[a..d]', 'GRevLex') # optional - macaulay2 - sage: R1.describe() # optional - macaulay2 + sage: R1 = macaulay2.ring('ZZ/7', '[a..d]', 'GRevLex') + sage: R1.describe() ZZ - --[a..d, Degrees => {4:1}, Heft => {1}, MonomialOrder => {MonomialSize => 16}, + --[a..d, Degrees => {4:1}, Heft => {1}, MonomialOrder => {MonomialSize => 16}] 7 {GRevLex => {4:1} } {Position => Up } - -------------------------------------------------------------------------------- - DegreeRank => 1] - sage: R1.char() # optional - macaulay2 + sage: R1.char() 7 This is a polynomial ring over the rational numbers:: - sage: R2 = macaulay2.ring('QQ', '[x, y]') # optional - macaulay2 - sage: R2.describe() # optional - macaulay2 - QQ[x..y, Degrees => {2:1}, Heft => {1}, MonomialOrder => {MonomialSize => 16}, + sage: R2 = macaulay2.ring('QQ', '[x, y]') + sage: R2.describe() + QQ[x..y, Degrees => {2:1}, Heft => {1}, MonomialOrder => {MonomialSize => 16}] {Lex => 2 } {Position => Up } - -------------------------------------------------------------------------------- - DegreeRank => 1] TESTS:: - sage: macaulay2.ring('QQ', '[a_0..a_2,b.. list[str]: """ Return a list of tab completions for Macaulay2. @@ -796,7 +781,6 @@ def _tab_completion(self): TESTS:: - sage: # optional - macaulay2 sage: names = macaulay2._tab_completion() sage: 'ring' in names True @@ -815,17 +799,15 @@ def _tab_completion(self): s -> not match("^(o|sage)[0-9]+$", s)) """) # Now split this string into separate names - r = sorted(r[1:-1].split(", ")) # Macaulay2 sorts things like A, a, B, b, ... - return r + return sorted(r[1:-1].split(", ")) - def use(self, R): + def use(self, R) -> None: """ Use the Macaulay2 ring R. EXAMPLES:: - sage: # optional - macaulay2 sage: R = macaulay2("QQ[x,y]") sage: P = macaulay2("ZZ/7[symbol x, symbol y]") sage: macaulay2("x").cls()._operator('===', P) @@ -844,10 +826,10 @@ def new_from(self, type, value): EXAMPLES:: - sage: l = macaulay2.new_from("MutableList", [1,2,3]) # optional - macaulay2 - sage: l # optional - macaulay2 + sage: l = macaulay2.new_from("MutableList", [1,2,3]) + sage: l MutableList{...3...} - sage: list(l) # optional - macaulay2 + sage: list(l) [1, 2, 3] """ type = self(type) @@ -862,7 +844,7 @@ def _macaulay2_input_ring(self, base_ring, vars, order='GRevLex'): TESTS:: sage: R = GF(101)['x'] - sage: macaulay2._macaulay2_input_ring(R.base_ring(), R.gens(), 'Lex') # optional - macaulay2 + sage: macaulay2._macaulay2_input_ring(R.base_ring(), R.gens(), 'Lex') 'sage...[symbol x, MonomialSize=>16, MonomialOrder=>Lex]' """ if not isinstance(base_ring, str): @@ -885,37 +867,36 @@ class Macaulay2Element(ExtraTabCompletion, ExpectElement, sage.interfaces.abc.Ma .. automethod:: _sage_ """ - def _latex_(self): + def _latex_(self) -> str: r""" EXAMPLES:: - sage: m = macaulay2('matrix {{1,2},{3,4}}') # optional - macaulay2 - sage: m # optional - macaulay2 + sage: m = macaulay2('matrix {{1,2},{3,4}}') + sage: m | 1 2 | | 3 4 | - sage: latex(m) # optional - macaulay2 - \left(\begin{smallmatrix} 1&2\\ 3&4\\ \end{smallmatrix}\right) + sage: latex(m) + \left(\!\begin{array}{cc}\n1&2\\\n3&4\n\end{array}\!\right) """ s = self.tex().external_string().strip('"').strip('$').replace('\\\\', '\\') s = s.replace(r"\bgroup", "").replace(r"\egroup", "") return s - def __iter__(self): + def __iter__(self) -> Iterator: """ EXAMPLES:: - sage: l = macaulay2([1,2,3]) # optional - macaulay2 - sage: list(iter(l)) # optional - macaulay2 + sage: l = macaulay2([1,2,3]) + sage: list(iter(l)) [1, 2, 3] """ for i in range(len(self)): # zero-indexed! yield self[i] - def __str__(self): + def __str__(self) -> str: """ EXAMPLES:: - sage: # optional - macaulay2 sage: R = macaulay2("QQ[x,y,z]/(x^3-y^3-z^3)") sage: x = macaulay2('x') sage: y = macaulay2('y') @@ -931,11 +912,10 @@ def __str__(self): P = self._check_valid() return P.get(self._name) - def _repr_(self): + def _repr_(self) -> str: """ EXAMPLES:: - sage: # optional - macaulay2 sage: repr(macaulay2('1..25')) (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, -------------------------------------------------------------------------------- @@ -946,7 +926,6 @@ def _repr_(self): If ``AfterPrint`` is enabled, the ``repr`` contains type information, but the string representation does not:: - sage: # optional - macaulay2 sage: macaulay2.options.after_print = True sage: repr(macaulay2('1..25')) (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, @@ -973,13 +952,13 @@ def _repr_(self): % (empty_ascii_art._terminal_width(), self._name), strip=False) - def external_string(self): + def external_string(self) -> str: """ EXAMPLES:: - sage: R = macaulay2("QQ[symbol x, symbol y]") # optional - macaulay2 - sage: R.external_string() # optional - macaulay2 - 'QQ(monoid[x..y, Degrees => {2:1}, Heft => {1}, MonomialOrder => VerticalList{MonomialSize => 32, GRevLex => {2:1}, Position => Up}, DegreeRank => 1])' + sage: R = macaulay2("QQ[symbol x, symbol y]") + sage: R.external_string() + 'QQ[x..y, Degrees => {2:1}, Heft => {1}]' """ P = self._check_valid() code = 'toExternalString(%s)' % self.name() @@ -990,8 +969,7 @@ def external_string(self): return P.eval('%s' % self.name()) raise RuntimeError("Error evaluating Macaulay2 code.\nIN:%s\nOUT:%s" % (code, X)) - s = multiple_replace({'\r': '', '\n': ' '}, X) - return s + return multiple_replace({'\r': '', '\n': ' '}, X) def name(self, new_name=None): """ @@ -1007,7 +985,6 @@ def name(self, new_name=None): EXAMPLES:: - sage: # optional - macaulay2 sage: S = macaulay2(QQ['x,y']) sage: S.name() 'sage...' @@ -1022,10 +999,10 @@ def name(self, new_name=None): The name can also be given at definition:: - sage: A = macaulay2(ZZ['x,y,z'], name='A') # optional - macaulay2 - sage: A.name() # optional - macaulay2 + sage: A = macaulay2(ZZ['x,y,z'], name='A') + sage: A.name() 'A' - sage: A^1 # optional - macaulay2 + sage: A^1 1 A """ @@ -1049,14 +1026,14 @@ def name(self, new_name=None): "IN:%s\nOUT:%s" % (cmd, ans)) return P._object_class()(P, new_name, is_name=True) - def __len__(self): + def __len__(self) -> int: """ EXAMPLES:: - sage: l = macaulay2([1,2,3]) # optional - macaulay2 - sage: len(l) # optional - macaulay2 + sage: l = macaulay2([1,2,3]) + sage: len(l) 3 - sage: type(_) # optional - macaulay2 + sage: type(_) <... 'int'> """ self._check_valid() @@ -1067,8 +1044,8 @@ def __getitem__(self, n): """ EXAMPLES:: - sage: l = macaulay2([1,2,3]) # optional - macaulay2 - sage: l[0] # optional - macaulay2 + sage: l = macaulay2([1,2,3]) + sage: l[0] 1 """ self._check_valid() @@ -1079,9 +1056,9 @@ def __setitem__(self, index, value): """ EXAMPLES:: - sage: l = macaulay2.new_from("MutableList", [1,2,3]) # optional - macaulay2 - sage: l[0] = 4 # optional - macaulay2 - sage: list(l) # optional - macaulay2 + sage: l = macaulay2.new_from("MutableList", [1,2,3]) + sage: l[0] = 4 + sage: list(l) [4, 2, 3] """ P = self.parent() @@ -1095,7 +1072,6 @@ def __call__(self, x): """ EXAMPLES:: - sage: # optional - macaulay2 sage: R = macaulay2("QQ[x, y]") sage: x,y = R.gens() sage: I = macaulay2.ideal(x*y, x+y) @@ -1118,7 +1094,6 @@ def __floordiv__(self, x): Now make the M2 version of R, so we can coerce elements of R to M2:: - sage: # optional - macaulay2 sage: _ = macaulay2(R) sage: h = macaulay2((x^3 + 2*y^2*x)^7); h 21 7 14 @@ -1146,7 +1121,6 @@ def __mod__(self, x): Now make the M2 version of R, so we can coerce elements of R to M2:: - sage: # optional - macaulay2 sage: _ = macaulay2(R) sage: h = macaulay2((x^3 + 2*y^2*x)^7); h 21 7 14 @@ -1166,13 +1140,12 @@ def __mod__(self, x): x = self.parent(x) return self.parent().new('%s %% %s' % (self.name(), x.name())) - def __bool__(self): + def __bool__(self) -> bool: """ Return whether this Macaulay2 element is not ``False`` or not ``0``. EXAMPLES:: - sage: # optional - macaulay2 sage: a = macaulay2(0) sage: a == 0 True @@ -1183,7 +1156,6 @@ def __bool__(self): Check that :issue:`28705` is fixed:: - sage: # optional - macaulay2 sage: t = macaulay2(True); t true sage: bool(t) @@ -1196,7 +1168,7 @@ def __bool__(self): P = self.parent() return P.eval('{0}===false or {0}==0'.format(self._name)) != 'true' - def sage_polystring(self): + def sage_polystring(self) -> str: """ If this Macaulay2 element is a polynomial, return a string representation of this polynomial that is suitable for @@ -1206,7 +1178,6 @@ def sage_polystring(self): EXAMPLES:: - sage: # optional - macaulay2 sage: R = macaulay2.ring('QQ','(x,y)') sage: f = macaulay2('x^3 + 3*y^11 + 5') sage: print(f) @@ -1224,7 +1195,6 @@ def subs(self, *args, **kwds): EXAMPLES:: - sage: # optional - macaulay2 sage: R = macaulay2("QQ[x]") sage: P = macaulay2("ZZ/7[symbol x]") sage: x, = R.gens() @@ -1235,7 +1205,7 @@ def subs(self, *args, **kwds): """ return self.__getattr__("substitute")(*args, **kwds) - def _tab_completion(self): + def _tab_completion(self) -> list[str]: """ Return a list of tab completions for ``self``. @@ -1247,7 +1217,6 @@ def _tab_completion(self): TESTS:: - sage: # optional - macaulay2 sage: a = macaulay2("QQ[x,y]") sage: traits = a._tab_completion() sage: "generators" in traits @@ -1256,7 +1225,7 @@ def _tab_completion(self): The implementation of this function does not set or change global variables:: - sage: a.dictionary()._operator('#?', '"r"') # optional - macaulay2 + sage: a.dictionary()._operator('#?', '"r"') false """ # It is possible, that these are not all possible methods, but @@ -1291,10 +1260,10 @@ def cls(self): EXAMPLES:: - sage: macaulay2(ZZ).cls() # optional - macaulay2 + sage: macaulay2(ZZ).cls() Ring """ - return self.parent()("class %s" % self.name()) + return self.parent()(f"class {self.name()}") def after_print_text(self): r""" @@ -1309,10 +1278,10 @@ def after_print_text(self): EXAMPLES:: - sage: B = macaulay2(matrix([[1, 2], [3, 6]])).kernel(); B # optional - macaulay2 + sage: B = macaulay2(matrix([[1, 2], [3, 6]])).kernel(); B image | 2 | | -1 | - sage: B.after_print_text() # optional - macaulay2 + sage: B.after_print_text() 2 ZZ-module, submodule of ZZ """ @@ -1326,7 +1295,6 @@ def dot(self, x): """ EXAMPLES:: - sage: # optional - macaulay2 sage: d = macaulay2.new("MutableHashTable") sage: d["k"] = 4 sage: d.dot("k") @@ -1336,14 +1304,13 @@ def dot(self, x): x = parent(x) return parent("%s.%s" % (self.name(), x)) - def _operator(self, opstr, x): + def _operator(self, opstr: str, x): """ Return the infix binary operation specified by opstr applied to ``self`` and x. EXAMPLES:: - sage: # optional - macaulay2 sage: a = macaulay2("3") sage: a._operator("+", a) 6 @@ -1358,8 +1325,8 @@ def sharp(self, x): """ EXAMPLES:: - sage: a = macaulay2([1,2,3]) # optional - macaulay2 - sage: a.sharp(0) # optional - macaulay2 + sage: a = macaulay2([1,2,3]) + sage: a.sharp(0) 1 """ return self._operator("#", x) @@ -1371,8 +1338,8 @@ def starstar(self, x): EXAMPLES:: - sage: a = macaulay2([1,2]).set() # optional - macaulay2 - sage: a.starstar(a) # optional - macaulay2 + sage: a = macaulay2([1,2]).set() + sage: a.starstar(a) set {(1, 1), (1, 2), (2, 1), (2, 2)} """ return self._operator("**", x) @@ -1381,8 +1348,8 @@ def underscore(self, x): """ EXAMPLES:: - sage: a = macaulay2([1,2,3]) # optional - macaulay2 - sage: a.underscore(0) # optional - macaulay2 + sage: a = macaulay2([1,2,3]) + sage: a.underscore(0) 1 """ return self._operator("_", x) @@ -1394,13 +1361,11 @@ def _sage_(self): r""" EXAMPLES:: - sage: # optional - macaulay2 sage: macaulay2(ZZ).sage() # indirect doctest Integer Ring sage: macaulay2(QQ).sage() Rational Field - sage: # optional - macaulay2 sage: macaulay2(2).sage() 2 sage: macaulay2(1/2).sage() @@ -1412,20 +1377,17 @@ def _sage_(self): sage: macaulay2([1,2,3]).sage() [1, 2, 3] - sage: # optional - macaulay2 sage: m = matrix([[1,2],[3,4]]) sage: macaulay2(m).sage() [1 2] [3 4] - sage: # optional - macaulay2 sage: D = macaulay2('hashTable {4 => 1, 2 => 3}') sage: D.pairs() {(4, 1), (2, 3)} sage: D.sage() == {4: 1, 2: 3} True - sage: # optional - macaulay2 sage: macaulay2(QQ['x,y']).sage() Multivariate Polynomial Ring in x, y over Rational Field sage: macaulay2(QQ['x']).sage() @@ -1433,29 +1395,25 @@ def _sage_(self): sage: macaulay2(GF(7)['x,y']).sage() Multivariate Polynomial Ring in x, y over Finite Field of size 7 - sage: # optional - macaulay2 sage: macaulay2(GF(7)).sage() Finite Field of size 7 sage: macaulay2(GF(49, 'a')).sage() Finite Field in a of size 7^2 sage: R. = QQ[] - sage: macaulay2(x^2+y^2+1).sage() # optional - macaulay2 + sage: macaulay2(x^2+y^2+1).sage() x^2 + y^2 + 1 - sage: # optional - macaulay2 sage: R = macaulay2("QQ[x,y]") sage: I = macaulay2("ideal (x,y)") sage: I.sage() Ideal (x, y) of Multivariate Polynomial Ring in x, y over Rational Field - sage: # optional - macaulay2 sage: macaulay2("x = symbol x") x sage: macaulay2("QQ[x_0..x_25]").sage() Multivariate Polynomial Ring in x_0, x_1,..., x_25 over Rational Field - sage: # optional - macaulay2 sage: S = ZZ['x,y'].quotient('x^2-y') sage: macaulay2(S).sage() == S True @@ -1463,7 +1421,6 @@ def _sage_(self): sage: macaulay2(S).sage() == S True - sage: # optional - macaulay2 sage: R = GF(13)['a,b']['c,d'] sage: macaulay2(R).sage() == R True @@ -1472,23 +1429,19 @@ def _sage_(self): sage: macaulay2.substitute('a', R).sage().parent() is R True - sage: # optional - macaulay2 sage: R = macaulay2("QQ^2") sage: R.sage() Vector space of dimension 2 over Rational Field - sage: # optional - macaulay2 sage: macaulay2("vector {4_QQ, 2}").sage() (4, 2) sage: _.parent() Vector space of dimension 2 over Rational Field - sage: # optional - macaulay2 sage: m = macaulay2('"hello"') sage: m.sage() 'hello' - sage: # optional - macaulay2 sage: gg = macaulay2.needsPackage('"Graphs"') sage: g = macaulay2.barbellGraph(3) sage: g.sage() @@ -1496,7 +1449,6 @@ def _sage_(self): sage: g.sage().edges(labels=False) [(0, 1), (0, 2), (1, 2), (2, 3), (3, 4), (3, 5), (4, 5)] - sage: # optional - macaulay2 sage: d = 'digraph ({{1,2},{2,1},{3,1}}, EntryMode => "edges")' sage: g = macaulay2(d) sage: g.sage() @@ -1507,21 +1459,21 @@ def _sage_(self): Chain complexes and maps of chain complexes can be converted:: sage: R = ZZ['a,b,c'] - sage: C = macaulay2(ideal(R.gens())).resolution() # optional - macaulay2 - sage: ascii_art(C.sage()) # optional - macaulay2 - [-b 0 -c] [ c] - [ a -c 0] [ a] - [a b c] [ 0 b a] [-b] - 0 <-- C_0 <-------- C_1 <----------- C_2 <----- C_3 <-- 0 - sage: F = C.dot('dd') # optional - macaulay2 - sage: G = F.sage() # optional - macaulay2 - sage: G.in_degree(2) # optional - macaulay2 + sage: C = macaulay2(ideal(R.gens())).resolution() + sage: unicode_art(C.sage()) + ⎛-b 0 -c⎞ ⎛ c⎞ + ⎜ a -c 0⎟ ⎜ a⎟ + (a b c) ⎝ 0 b a⎠ ⎝-b⎠ + 0 <── C_0 <────── C_1 <───────── C_2 <─── C_3 <── 0 + sage: F = C.dot('dd') + sage: G = F.sage() + sage: G.in_degree(2) [-b 0 -c] [ a -c 0] [ 0 b a] - sage: F.underscore(2).sage() == G.in_degree(2) # optional - macaulay2 + sage: F.underscore(2).sage() == G.in_degree(2) True - sage: (F^2).sage() # optional - macaulay2 + sage: (F^2).sage() Chain complex morphism: From: Chain complex with at most 4 nonzero terms over Multivariate Polynomial Ring in a, b, c over Integer Ring To: Chain complex with at most 4 nonzero terms over Multivariate Polynomial Ring in a, b, c over Integer Ring @@ -1529,7 +1481,6 @@ def _sage_(self): Quotient rings in Macaulay2 inherit variable names from the ambient ring, so we mimic this behaviour in Sage:: - sage: # optional - macaulay2 sage: R = macaulay2("ZZ/7[x,y]") sage: I = macaulay2("ideal (x^3 - y^2)") sage: (R/I).gens() @@ -1539,10 +1490,10 @@ def _sage_(self): Elements of quotient rings:: - sage: x, y = (R/I).gens() # optional - macaulay2 - sage: f = ((x^3 + 2*y^2*x)^7).sage(); f # optional - macaulay2 + sage: x, y = (R/I).gens() + sage: f = ((x^3 + 2*y^2*x)^7).sage(); f 2*x*y^18 + y^14 - sage: f.parent() # optional - macaulay2 + sage: f.parent() Quotient of Multivariate Polynomial Ring in x, y over Finite Field of size 7 by the ideal (x^3 - y^2) """ repr_str = str(self) @@ -1552,23 +1503,23 @@ def _sage_(self): if repr_str == "ZZ": from sage.rings.integer_ring import ZZ return ZZ - elif repr_str == "QQ": + if repr_str == "QQ": from sage.rings.rational_field import QQ return QQ if cls_cls_str == "Type": if cls_str == "List": return [entry._sage_() for entry in self] - elif cls_str == "Matrix": + if cls_str == "Matrix": base_ring = self.ring()._sage_() return self._matrix_(base_ring) - elif cls_str == 'HashTable': - return {x._sage_(): y._sage_() for (x, y) in self.pairs()} - elif cls_str == "Ideal": + if cls_str == 'HashTable': + return {x._sage_(): y._sage_() for x, y in self.pairs()} + if cls_str == "Ideal": parent = self.ring()._sage_() gens = self.gens().entries().flatten()._sage_() return parent.ideal(*gens) - elif cls_str == "QuotientRing": + if cls_str == "QuotientRing": # Handle the ZZ/n case ambient = self.ambient() if ambient.external_string() == 'ZZ': @@ -1584,7 +1535,7 @@ def _sage_(self): ambient_ring = ambient._sage_() ideal = self.ideal()._sage_() return ambient_ring.quotient(ideal, names=ambient_ring.variable_names()) - elif cls_str == "PolynomialRing": + if cls_str == "PolynomialRing": from sage.rings.polynomial.polynomial_ring_constructor import ( PolynomialRing, ) @@ -1612,7 +1563,7 @@ def _sage_(self): raise ValueError("cannot convert Macaulay2's term order to a Sage term order") return PolynomialRing(base_ring, order=order, names=gens) - elif cls_str == "GaloisField": + if cls_str == "GaloisField": from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.integer_ring import ZZ gf, n = repr_str.split(" ") @@ -1622,20 +1573,20 @@ def _sage_(self): else: gen = str(self.gens())[1:-1] return GF(n, gen) - elif cls_str == "Boolean": + if cls_str == "Boolean": if repr_str == "true": return True - elif repr_str == "false": + if repr_str == "false": return False - elif cls_str == "String": + if cls_str == "String": return str(repr_str) - elif cls_str == "Module": + if cls_str == "Module": from sage.modules.free_module import FreeModule if self.isFreeModule()._sage_(): ring = self.ring()._sage_() rank = self.rank()._sage_() return FreeModule(ring, rank) - elif cls_str in ("Graph", "Digraph"): + if cls_str in ("Graph", "Digraph"): if cls_str == "Graph": from sage.graphs.graph import Graph graph_cls = Graph @@ -1646,7 +1597,7 @@ def _sage_(self): g = graph_cls(adj_mat, format='adjacency_matrix') g.relabel(self.vertices()) return g - elif cls_str == "ChainComplex": + if cls_str == "ChainComplex": from sage.homology.chain_complex import ChainComplex ring = self.ring()._sage_() dd = self.dot('dd') @@ -1656,7 +1607,7 @@ def _sage_(self): matrices = {i: dd.underscore(i)._matrix_(ring) for i in range(a, b + 1)} return ChainComplex(matrices, degree=degree) - elif cls_str == "ChainComplexMap": + if cls_str == "ChainComplexMap": from sage.homology.chain_complex_morphism import ChainComplexMorphism ring = self.ring()._sage_() source = self.source() @@ -1677,15 +1628,22 @@ def _sage_(self): return ZZ(repr_str) elif cls_str == "QQ": from sage.rings.rational_field import QQ - repr_str = self.external_string() - if "/" not in repr_str: - repr_str = repr_str + "/1" - return QQ(repr_str) + return QQ((self.numerator()._sage_(), + self.denominator()._sage_())) m2_parent = self.cls() parent = m2_parent._sage_() - if cls_cls_str in ("PolynomialRing", "QuotientRing"): + if cls_cls_str == "PolynomialRing": + # going through a dict + if len(m2_parent.gens()) == 1: + d = {monome[0].sage(): coeff.sage() + for monome, coeff in self.listForm()} + else: + d = {tuple(monome.sage()): coeff.sage() + for monome, coeff in self.listForm()} + return parent(d) + if cls_cls_str == "QuotientRing": return parent(self.external_string()) elif cls_cls_str == "Module": entries = self.entries()._sage_() @@ -1695,7 +1653,7 @@ def _sage_(self): try: return sage_eval(repr_str) except Exception: - raise NotImplementedError("cannot convert %s to a Sage object" % repr_str) + raise NotImplementedError(f"cannot convert\n{repr_str}\nto a Sage object") def _matrix_(self, R): r""" @@ -1710,8 +1668,8 @@ def _matrix_(self, R): EXAMPLES:: - sage: A = macaulay2('matrix {{1,2},{3,4}}') # optional - macaulay2 - sage: matrix(QQ, A) # optional - macaulay2, indirect doctest + sage: A = macaulay2('matrix {{1,2},{3,4}}') + sage: matrix(QQ, A) # indirect doctest [1 2] [3 4] @@ -1719,10 +1677,10 @@ def _matrix_(self, R): Check that degenerate matrix dimensions are preserved (:issue:`28591`):: - sage: m = macaulay2('matrix {{},{}}') # optional - macaulay2 - sage: matrix(ZZ, m).dimensions() # optional - macaulay2 + sage: m = macaulay2('matrix {{},{}}') + sage: matrix(ZZ, m).dimensions() (2, 0) - sage: matrix(ZZ, m.transpose()).dimensions() # optional - macaulay2 + sage: matrix(ZZ, m.transpose()).dimensions() (0, 2) """ from sage.matrix.constructor import matrix @@ -1737,10 +1695,10 @@ class Macaulay2Function(ExpectFunction): """ TESTS:: - sage: gb = macaulay2.gb # optional - macaulay2 - sage: type(gb) # optional - macaulay2 + sage: gb = macaulay2.gb + sage: type(gb) - sage: gb._name # optional - macaulay2 + sage: gb._name 'gb' """ @@ -1748,7 +1706,7 @@ def _instancedoc_(self): """ EXAMPLES:: - sage: print(macaulay2.load.__doc__) # optional - macaulay2 + sage: print(macaulay2.load.__doc__) nodetex,noreplace load... ****... @@ -1763,7 +1721,7 @@ def _instancedoc_(self): sage: from sage.repl.interpreter import get_test_shell sage: shell = get_test_shell() - sage: shell.run_cell('macaulay2.matrix?') # optional - macaulay2 + sage: shell.run_cell('macaulay2.matrix?') ... +--------------------------------+ | i1 : matrix{{1,2,3},{4,5,6}} | @@ -1772,7 +1730,7 @@ def _instancedoc_(self): | | 4 5 6 | | | | | 2 3 | - | o1 : Matrix ZZ <--- ZZ | + | o1 : Matrix ZZ <-- ZZ | +--------------------------------+ ... """ @@ -1783,7 +1741,7 @@ def _sage_src_(self): """ EXAMPLES:: - sage: macaulay2.gb._sage_src_() # optional - macaulay2 + sage: macaulay2.gb._sage_src_() -- code for method: gb(Ideal)... -- code for method: gb(Matrix)... ... @@ -1803,11 +1761,12 @@ def _instancedoc_(self): sage: from sage.repl.interpreter import get_test_shell sage: shell = get_test_shell() - sage: shell.run_cell('I = macaulay2("ideal {4}")') # optional - macaulay2 - sage: shell.run_cell('I.resolution?') # optional - macaulay2 - Signature: I.resolution(*args, **kwds) - Type: Macaulay2FunctionElement - String form: resolution + sage: shell.run_cell('I = macaulay2("ideal {4}")') + sage: shell.run_cell('I.resolution?') + Signature: I.resolution(Ideal) + Call signature: I.resolution(self, *args, **kwds) + Type: Macaulay2FunctionElement + String form: resolution File: ... Docstring: resolution -- projective resolution @@ -1833,9 +1792,9 @@ def _sage_src_(self): """ EXAMPLES:: - sage: m = macaulay2('matrix {{4,6}}') # optional - macaulay2 - sage: m.resolution._sage_src_() # optional - macaulay2 - -- code for method: resolution(Matrix)... + sage: m = macaulay2('matrix {{4,6}}') + sage: m.resolution._sage_src_() + -- code for method: freeResolution(Matrix)... """ return self._obj.parent().eval( 'code select(methods %s, m->instance(%s, m#1))'