diff --git a/src/doc/en/constructions/plotting.rst b/src/doc/en/constructions/plotting.rst index 58eb17a98c6..2a291900cf9 100644 --- a/src/doc/en/constructions/plotting.rst +++ b/src/doc/en/constructions/plotting.rst @@ -214,7 +214,7 @@ Terminal application.) :: sage: maxima.eval('load("plotdf");') - '".../share/maxima.../share/dynamics/plotdf.lisp"' + .../share/maxima.../share/dynamics/plotdf.lisp... sage: maxima.eval('plotdf(x+y,[trajectory_at,2,-0.1]); ') # not tested This plots a direction field (the plotdf Maxima package was also diff --git a/src/doc/en/developer/coding_basics.rst b/src/doc/en/developer/coding_basics.rst index e1da3a54fdc..12a95dcba78 100644 --- a/src/doc/en/developer/coding_basics.rst +++ b/src/doc/en/developer/coding_basics.rst @@ -186,14 +186,6 @@ included in one of the following places: :func:`importlib.resources.as_file`. It should be imported in the same way as shown above. -- Older code in the Sage library accesses - the package data in more direct ways. For example, - :sage_root:`src/sage/interfaces/maxima.py` uses the file - :sage_root:`src/sage/interfaces/maxima.lisp` at runtime, so it - refers to it as:: - - os.path.join(os.path.dirname(__file__), 'sage-maxima.lisp') - - In an appropriate subdirectory of :sage_root:`src/sage/ext_data/`. (At runtime, it is then available in the directory indicated by ``SAGE_EXTCODE``). For example, if ``file`` is placed in diff --git a/src/doc/en/reference/calculus/index.rst b/src/doc/en/reference/calculus/index.rst index 0f451a50613..da5d96b2144 100644 --- a/src/doc/en/reference/calculus/index.rst +++ b/src/doc/en/reference/calculus/index.rst @@ -56,7 +56,6 @@ Internal functionality supporting calculus - :doc:`sage/symbolic/expression_conversions` - :doc:`sage/symbolic/benchmark` - :doc:`sage/symbolic/random_tests` -- :doc:`sage/symbolic/maxima_wrapper` - :doc:`External integrators ` - :doc:`External interpolators ` @@ -94,7 +93,6 @@ Internal functionality supporting calculus sage/calculus/interpolators sage/calculus/functions sage/calculus/var - sage/symbolic/maxima_wrapper sage/symbolic/operators sage/symbolic/benchmark sage/symbolic/random_tests diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index 6dc892248ca..3c834d6bfcb 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -349,6 +349,10 @@ Note that ``x`` is still ``x``, since the maxima used by the calculus package is different than the one in the interactive interpreter. +Clear the maxima variables to avoid interference with other tests:: + + sage: maxima('kill(x,y)') + done Check to see that the problem with the variables method mentioned in :issue:`3779` is actually fixed:: @@ -395,7 +399,7 @@ Check if maxima has redundant variables defined after initialization, see :issue:`9538`:: - sage: maxima = sage.interfaces.maxima.maxima + sage: maxima = sage.interfaces.maxima_lib.maxima sage: maxima('f1') f1 sage: sage.calculus.calculus.maxima('f1') @@ -419,26 +423,23 @@ """ import re +from types import FunctionType + from sage.arith.misc import algebraic_dependency +from sage.interfaces.maxima_lib import maxima +from sage.misc.latex import latex +from sage.misc.parser import LookupNameMaker, Parser +from sage.rings.cc import CC from sage.rings.integer import Integer from sage.rings.rational_field import QQ from sage.rings.real_double import RealDoubleElement from sage.rings.real_mpfr import RR, create_RealNumber -from sage.rings.cc import CC - -from sage.misc.latex import latex -from sage.misc.parser import Parser, LookupNameMaker from sage.structure.element import Expression -from sage.symbolic.ring import var, SR -from sage.symbolic.symbols import symbol_table from sage.symbolic.function import Function from sage.symbolic.function_factory import function_factory -from sage.symbolic.integration.integral import (indefinite_integral, - definite_integral) - -from sage.misc.lazy_import import lazy_import -lazy_import('sage.interfaces.maxima_lib', 'maxima') -from types import FunctionType +from sage.symbolic.integration.integral import definite_integral, indefinite_integral +from sage.symbolic.ring import SR, var +from sage.symbolic.symbols import symbol_table ######################################################## @@ -667,6 +668,7 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False): elif algorithm == 'sympy': expression,v,a,b = (expr._sympy_() for expr in (expression, v, a, b)) from sympy import summation + from sage.interfaces.sympy import sympy_init sympy_init() result = summation(expression, (v, a, b)) @@ -920,6 +922,7 @@ def symbolic_product(expression, v, a, b, algorithm='maxima', hold=False): elif algorithm == 'sympy': expression,v,a,b = (expr._sympy_() for expr in (expression, v, a, b)) from sympy import product as sproduct + from sage.interfaces.sympy import sympy_init sympy_init() result = sproduct(expression, (v, a, b)) @@ -1674,7 +1677,11 @@ def mma_free_limit(expression, v, a, dir=None): sage: mma_free_limit(e^(-x), x, a=oo) # optional - internet 0 """ - from sage.interfaces.mathematica import request_wolfram_alpha, parse_moutput_from_json, symbolic_expression_from_mathematica_string + from sage.interfaces.mathematica import ( + parse_moutput_from_json, + request_wolfram_alpha, + symbolic_expression_from_mathematica_string, + ) dir_plus = ['plus', '+', 'above', 'right'] dir_minus = ['minus', '-', 'below', 'left'] math_expr = expression._mathematica_init_() @@ -1915,6 +1922,7 @@ def laplace(ex, t, s, algorithm='maxima'): elif algorithm == 'sympy': ex_sy, t, s = (expr._sympy_() for expr in (ex, t, s)) from sympy import laplace_transform + from sage.interfaces.sympy import sympy_init sympy_init() result = laplace_transform(ex_sy, t, s) @@ -2100,6 +2108,7 @@ def inverse_laplace(ex, s, t, algorithm='maxima'): elif algorithm == 'sympy': ex_sy, s, t = (expr._sympy_() for expr in (ex, s, t)) from sympy import inverse_laplace_transform + from sage.interfaces.sympy import sympy_init sympy_init() result = inverse_laplace_transform(ex_sy, s, t) @@ -2460,10 +2469,12 @@ def symbolic_expression_from_maxima_string(x, equals_sub=False, maxima=maxima): Make sure that we don't accidentally pick up variables in the maxima namespace (:issue:`8734`):: - sage: sage.calculus.calculus.maxima('my_new_var : 2') + sage: maxima('my_new_var : 2') 2 sage: var('my_new_var').full_simplify() my_new_var + sage: maxima('kill(my_new_var)') + done ODE solution constants are treated differently (:issue:`16007`):: diff --git a/src/sage/calculus/desolvers.py b/src/sage/calculus/desolvers.py index 8585a1021a2..f6d222adbfd 100644 --- a/src/sage/calculus/desolvers.py +++ b/src/sage/calculus/desolvers.py @@ -71,19 +71,15 @@ # https://www.gnu.org/licenses/ ########################################################################## -import shutil import os +import shutil -from sage.interfaces.maxima import Maxima +from sage.calculus.functional import diff +from sage.interfaces.maxima_lib import maxima from sage.misc.functional import N from sage.rings.real_mpfr import RealField from sage.structure.element import Expression -from .functional import diff - - -maxima = Maxima() - def fricas_desolve(de, dvar, ics, ivar): r""" @@ -156,8 +152,8 @@ def fricas_desolve_system(des, dvars, ics, ivar): [x(t) == cos(t)^2 + sin(t)^2 + 2*sin(t), y(t) == -2*cos(t) + 1] """ from sage.interfaces.fricas import fricas - from sage.symbolic.ring import SR from sage.symbolic.relation import solve + from sage.symbolic.ring import SR ops = [dvar.operator() for dvar in dvars] y = fricas(des).solve(ops, ivar).sage() basis = y["basis"] @@ -1364,9 +1360,9 @@ def desolve_rk4_inner(de, dvar): return plot_slope_field(de, (ivar, XMIN, XMAX), (dvar, YMIN, YMAX)) + R if not (isinstance(dvar, Expression) and dvar.is_symbol()): - from sage.symbolic.ring import SR from sage.calculus.functional import diff from sage.symbolic.relation import solve + from sage.symbolic.ring import SR if isinstance(de, Expression) and de.is_relational(): de = de.lhs() - de.rhs() # consider to add warning if the solution is not unique @@ -1614,8 +1610,9 @@ def desolve_odeint(des, ics, times, dvars, ivar=None, compute_jac=False, args=() """ from scipy.integrate import odeint - from sage.ext.fast_eval import fast_float + from sage.calculus.functions import jacobian + from sage.ext.fast_eval import fast_float def desolve_odeint_inner(ivar): # one-dimensional systems: @@ -1838,9 +1835,9 @@ def desolve_tides_mpfr(f, ics, initial, final, delta, tolrel=1e-16, tolabs=1e-16 import subprocess if subprocess.call('command -v gcc', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE): raise RuntimeError('Unable to run because gcc cannot be found') - from sage.interfaces.tides import genfiles_mpfr - from sage.functions.other import ceil from sage.functions.log import log + from sage.functions.other import ceil + from sage.interfaces.tides import genfiles_mpfr from sage.misc.temporary_file import tmp_dir tempdir = tmp_dir() intfile = os.path.join(tempdir, 'integrator.c') diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 9207b767997..a31f9899459 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -3936,6 +3936,7 @@ def __init__(self, box): TESTS:: sage: from sage.categories.pushout import BlackBoxConstructionFunctor + sage: from sage.interfaces.maxima_lib import maxima sage: FG = BlackBoxConstructionFunctor(gap) sage: FM = BlackBoxConstructionFunctor(maxima) # needs sage.symbolic sage: FM == FG # needs sage.libs.gap sage.symbolic @@ -3967,6 +3968,7 @@ def __eq__(self, other): TESTS:: sage: from sage.categories.pushout import BlackBoxConstructionFunctor + sage: from sage.interfaces.maxima_lib import maxima sage: FG = BlackBoxConstructionFunctor(gap) sage: FM = BlackBoxConstructionFunctor(maxima) # needs sage.symbolic sage: FM == FG # indirect doctest # needs sage.libs.gap sage.symbolic @@ -3986,6 +3988,7 @@ def __ne__(self, other): EXAMPLES:: sage: from sage.categories.pushout import BlackBoxConstructionFunctor + sage: from sage.interfaces.maxima_lib import maxima sage: FG = BlackBoxConstructionFunctor(gap) sage: FM = BlackBoxConstructionFunctor(maxima) # needs sage.symbolic sage: FM != FG # indirect doctest # needs sage.libs.gap sage.symbolic diff --git a/src/sage/features/sagemath.py b/src/sage/features/sagemath.py index 05179c410fd..4bd93c9d6b0 100644 --- a/src/sage/features/sagemath.py +++ b/src/sage/features/sagemath.py @@ -1140,7 +1140,6 @@ def __init__(self): PythonModule('sage.interfaces.maple'), PythonModule('sage.interfaces.mathematica'), PythonModule('sage.interfaces.mathics'), - PythonModule('sage.interfaces.maxima'), PythonModule('sage.interfaces.maxima_abstract'), PythonModule('sage.interfaces.maxima_lib'), PythonModule('sage.interfaces.qepcad'), diff --git a/src/sage/functions/orthogonal_polys.py b/src/sage/functions/orthogonal_polys.py index 8be9f23008a..c6ad8013a44 100644 --- a/src/sage/functions/orthogonal_polys.py +++ b/src/sage/functions/orthogonal_polys.py @@ -396,13 +396,12 @@ import warnings import sage.rings.abc - from sage.arith.misc import rising_factorial from sage.misc.lazy_import import lazy_import from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.symbolic.function import BuiltinFunction, GinacFunction from sage.structure.element import Expression, parent +from sage.symbolic.function import BuiltinFunction, GinacFunction lazy_import('sage.functions.other', ['factorial', 'binomial']) @@ -2444,8 +2443,8 @@ def _eval_(self, n, x, *args, **kwds): sage: laguerre(-9,2) # needs sage.symbolic 66769/315*e^2 """ - from sage.rings.integer import Integer from sage.functions.log import exp + from sage.rings.integer import Integer ret = self._eval_special_values_(n, x) if ret is not None: return ret @@ -2558,6 +2557,7 @@ def __init__(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: # needs sage.symbolic sage: a, n, x = var('a, n, x') sage: gen_laguerre(x, x, x)._sympy_() # needs sympy @@ -2565,7 +2565,7 @@ def __init__(self): sage: maxima(gen_laguerre(1, 2, x, hold=True)) 3*(1-_SAGE_VAR_x/3) sage: maxima(gen_laguerre(n, a, gen_laguerre(n, a, x))) - gen_laguerre(_SAGE_VAR_n,_SAGE_VAR_a, gen_laguerre(_SAGE_VAR_n,_SAGE_VAR_a,_SAGE_VAR_x)) + gen_laguerre(_SAGE_VAR_n,_SAGE_VAR_a,gen_laguerre(_SAGE_VAR_n,_SAGE_VAR_a,_SAGE_VAR_x)) TESTS:: @@ -2914,8 +2914,8 @@ def _eval_(self, n, x, b, c, *args, **kwds): if kwds.get('hold', False): return None if n not in ZZ or n < 0: - from sage.functions.hypergeometric import hypergeometric from sage.functions.gamma import gamma + from sage.functions.hypergeometric import hypergeometric return gamma(b + n) / gamma(b) * hypergeometric([-n, -x], [b], 1 - 1/c) try: return self.eval_formula(n, x, b, c) diff --git a/src/sage/interfaces/all.py b/src/sage/interfaces/all.py index e8c8dfdd260..63829f4bd1b 100644 --- a/src/sage/interfaces/all.py +++ b/src/sage/interfaces/all.py @@ -1,14 +1,8 @@ # interfaces to other interpreters -# import problems -try: - # from maxima_lib import maxima_lib - from sage.interfaces.maxima import maxima, Maxima -except ImportError: - pass - from sage.misc.lazy_import import lazy_import +lazy_import('sage.interfaces.maxima', 'maxima') lazy_import('sage.interfaces.sage0', ['sage0', 'sage0_version', 'Sage']) lazy_import('sage.interfaces.axiom', ['Axiom', 'axiom']) lazy_import('sage.interfaces.ecm', ['ECM', 'ecm']) diff --git a/src/sage/interfaces/expect.py b/src/sage/interfaces/expect.py index 5793a2c6128..2e222d5cf68 100644 --- a/src/sage/interfaces/expect.py +++ b/src/sage/interfaces/expect.py @@ -38,31 +38,34 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** +import gc import io import os import re import shlex import signal import sys -import weakref import time -import gc -from . import quit +import weakref from random import randrange import pexpect from pexpect import ExceptionPexpect -import sage.interfaces.abc -from sage.interfaces.interface import (Interface, InterfaceElement, - InterfaceFunction, InterfaceFunctionElement) - -from sage.structure.element import RingElement -from sage.env import SAGE_EXTCODE, LOCAL_IDENTIFIER -from sage.misc.object_multiplexer import Multiplex +import sage.interfaces.abc +from sage.cpython.string import bytes_to_str, str_to_bytes +from sage.env import LOCAL_IDENTIFIER, SAGE_EXTCODE +from sage.interfaces.interface import ( + Interface, + InterfaceElement, + InterfaceFunction, + InterfaceFunctionElement, +) from sage.misc.instancedoc import instancedoc +from sage.misc.object_multiplexer import Multiplex +from sage.structure.element import RingElement -from sage.cpython.string import str_to_bytes, bytes_to_str +from . import quit BAD_SESSION = -2 @@ -641,17 +644,17 @@ def quit(self, verbose=False): EXAMPLES:: - sage: a = maxima('y') - sage: maxima.quit(verbose=True) - Exiting Maxima with PID ... running ...maxima... + sage: a = gap('(1,2)(3,7)(4,6)(5,8)') + sage: gap.quit(verbose=True) + Exiting Gap with PID ... running ...gap... sage: a._check_valid() Traceback (most recent call last): ... - ValueError: The maxima session in which this object was defined is no longer running. + ValueError: The gap session in which this object was defined is no longer running. Calling ``quit()`` a second time does nothing:: - sage: maxima.quit(verbose=True) + sage: gap.quit(verbose=True) """ if self._expect is not None: if verbose: @@ -669,18 +672,18 @@ def detach(self): EXAMPLES:: - sage: a = maxima('y') - sage: saved_expect = maxima._expect # Save this to close later - sage: maxima.detach() + sage: a = gap('(1,2)(3,7)(4,6)(5,8)') + sage: saved_expect = gap._expect # Save this to close later + sage: gap.detach() sage: a._check_valid() Traceback (most recent call last): ... - ValueError: The maxima session in which this object was defined is no longer running. + ValueError: The gap session in which this object was defined is no longer running. sage: saved_expect.close() # Close child process Calling ``detach()`` a second time does nothing:: - sage: maxima.detach() + sage: gap.detach() """ try: self._expect._keep_alive() @@ -696,8 +699,6 @@ def _quit_string(self): sage: gp._quit_string() '\\q' - sage: maxima._quit_string() - 'quit();' """ return 'quit' @@ -1048,11 +1049,10 @@ def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if out = self._before() else: out = self._before().rstrip('\n\r') + elif self._terminal_echo: + out = '\n\r' else: - if self._terminal_echo: - out = '\n\r' - else: - out = '' + out = '' except KeyboardInterrupt: self._keyboard_interrupt() raise KeyboardInterrupt("Ctrl-c pressed while running %s" % self) @@ -1433,7 +1433,7 @@ def _object_class(self): EXAMPLES:: sage: from sage.interfaces.expect import Expect - sage: Expect._object_class(maxima) + sage: Expect._object_class(gap) """ return ExpectElement @@ -1443,7 +1443,7 @@ def _function_class(self): EXAMPLES:: sage: from sage.interfaces.expect import Expect - sage: Expect._function_class(maxima) + sage: Expect._function_class(gap) """ return ExpectFunction @@ -1453,7 +1453,7 @@ def _function_element_class(self): EXAMPLES:: sage: from sage.interfaces.expect import Expect - sage: Expect._function_element_class(maxima) + sage: Expect._function_element_class(gap) """ return FunctionElement diff --git a/src/sage/interfaces/interface.py b/src/sage/interfaces/interface.py index d68461130cc..ed6ea6457a4 100644 --- a/src/sage/interfaces/interface.py +++ b/src/sage/interfaces/interface.py @@ -42,14 +42,13 @@ import operator -from sage.structure.sage_object import SageObject -from sage.structure.parent_base import ParentWithBase -from sage.structure.element import Element, parent -from sage.structure.richcmp import rich_to_bool - import sage.misc.sage_eval from sage.misc.fast_methods import WithEqualityById from sage.misc.instancedoc import instancedoc +from sage.structure.element import Element, parent +from sage.structure.parent_base import ParentWithBase +from sage.structure.richcmp import rich_to_bool +from sage.structure.sage_object import SageObject class AsciiArtString(str): @@ -74,15 +73,9 @@ def __init__(self, name): EXAMPLES:: - sage: Maxima() == maxima - False + sage: from sage.interfaces.maxima_lib import maxima sage: maxima == maxima True - - sage: Maxima() != maxima - True - sage: maxima != maxima - False """ self.__name = name self.__coerce_name = '_' + name.lower() + '_' @@ -278,6 +271,7 @@ def __call__(self, x, name=None): sage: giac(True) # needs giac true + sage: from sage.interfaces.maxima_lib import maxima sage: maxima(True) true """ @@ -608,6 +602,7 @@ def function_call(self, function, args=None, kwds=None): """ EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima.quad_qags(x, x, 0, 1, epsrel=1e-4) [0.5,5.5511151231257...e-15,21,0] sage: maxima.function_call('quad_qags', [x, x, 0, 1], {'epsrel':'1e-4'}) @@ -626,6 +621,7 @@ def _function_call_string(self, function, args, kwds): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima._function_call_string('diff', ['f(x)', 'x'], []) 'diff(f(x),x)' """ @@ -774,7 +770,7 @@ def __len__(self): return len(self.sage()) def __reduce__(self): - """ + r""" The default linearisation is to return ``self``'s parent, which will then get the items returned by :meth:`_reduce` as arguments to reconstruct the element. @@ -820,15 +816,17 @@ def __reduce__(self): [1] "abc" sage: loads(dumps(r([1,2,3]))) # optional - rpy2 [1] 1 2 3 + sage: from sage.interfaces.maxima_lib import maxima sage: loads(dumps(maxima([1,2,3]))) [1,2,3] Unfortunately, strings in maxima can't be pickled yet:: + sage: from sage.interfaces.maxima_lib import maxima sage: loads(dumps(maxima('"abc"'))) Traceback (most recent call last): ... - TypeError: unable to make sense of Maxima expression '"abc"' in Sage + TypeError: unable to make sense of Maxima expression '\"abc\"' in Sage """ return self.parent(), (self._reduce(),) @@ -1193,6 +1191,7 @@ def _repr_(self): sage: M = matrix(QQ,2,range(4)) # optional - maple sage: maple(M) # optional - maple Matrix(2, 2, [[0,1],[2,3]]) + sage: from sage.interfaces.maxima_lib import maxima sage: maxima('sqrt(2) + 1/3') sqrt(2)+1/3 sage: mupad.package('"MuPAD-Combinat"') # optional - mupad-Combinat @@ -1222,6 +1221,7 @@ def get_using_file(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: a = maxima(str(2^1000)) sage: a.get_using_file() '10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376' @@ -1239,6 +1239,7 @@ def hasattr(self, attrname): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: m = maxima('2') sage: m.hasattr('integral') True @@ -1281,6 +1282,7 @@ def __int__(self): """ EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: int(maxima('1')) 1 sage: type(_) @@ -1313,6 +1315,7 @@ def __bool__(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: bool(maxima(0)) False sage: bool(maxima(1)) @@ -1335,6 +1338,7 @@ def __float__(self): """ EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: m = maxima('1/2') sage: m.__float__() 0.5 @@ -1347,6 +1351,7 @@ def _integer_(self, ZZ=None): """ EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: m = maxima('1') sage: m._integer_() 1 @@ -1362,6 +1367,7 @@ def _rational_(self): """ EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: m = maxima('1/2') sage: m._rational_() 1/2 @@ -1461,6 +1467,7 @@ def _add_(self, right): """ EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: f = maxima.cos(x) sage: g = maxima.sin(x) sage: f + g @@ -1501,6 +1508,7 @@ def _sub_(self, right): """ EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: f = maxima.cos(x) sage: g = maxima.sin(x) sage: f - g @@ -1536,6 +1544,7 @@ def _neg_(self): """ EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: f = maxima('sin(x)') sage: -f -sin(x) @@ -1549,6 +1558,7 @@ def _mul_(self, right): """ EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: f = maxima.cos(x) sage: g = maxima.sin(x) sage: f*g @@ -1582,6 +1592,7 @@ def _div_(self, right): """ EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: f = maxima.cos(x) sage: g = maxima.sin(x) sage: f/g @@ -1615,6 +1626,7 @@ def __invert__(self): """ EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: f = maxima('sin(x)') sage: ~f 1/sin(x) @@ -1639,6 +1651,7 @@ def __pow__(self, n): """ EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: a = maxima('2') sage: a^(3/4) 2^(3/4) diff --git a/src/sage/interfaces/maxima.py b/src/sage/interfaces/maxima.py index 7b54d8b3ac8..154a2cc34e0 100644 --- a/src/sage/interfaces/maxima.py +++ b/src/sage/interfaces/maxima.py @@ -29,8 +29,17 @@ - Robert Bradshaw, Nils Bruin, Jean-Pierre Flori (2010,2011): Binary library interface +There is also an ECL-based version of the Maxima interface in +:mod:`sage.interfaces.maxima_lib`. +That ECL interface is used for all internal symbolic calculations in SageMath, +providing a more direct and efficient connection to Maxima's core functionality. +The Pexpect interface defined here is isolated from the ECL-based interface: +it communicates with Maxima via a subprocess and text-based interaction, and is +primarily intended for interactive use. + This is the interface used by the maxima object:: + sage: from sage.interfaces.maxima import maxima sage: type(maxima) @@ -49,6 +58,7 @@ :: + sage: from sage.interfaces.maxima import maxima sage: x,y = SR.var('x,y') sage: F = maxima.factor('x^5 - y^5') sage: F # not tested - depends on maxima version @@ -76,6 +86,7 @@ :: + sage: from sage.interfaces.maxima import maxima sage: F = maxima('x * y') sage: repr(F) 'x*y' @@ -97,6 +108,7 @@ :: + sage: from sage.interfaces.maxima import maxima sage: f = maxima('x^5 + y^5') sage: f^2 (y^5+x^5)^2 @@ -120,6 +132,7 @@ :: + sage: from sage.interfaces.maxima import maxima sage: maxima('1/100 + 1/101') 201/10100 @@ -171,6 +184,7 @@ Here is an example of solving an algebraic equation:: + sage: from sage.interfaces.maxima import maxima sage: maxima('x^2+y^2=1').solve('y') [y = -sqrt(1-x^2),y = sqrt(1-x^2)] sage: maxima('x^2 + y^2 = (x^2 - y^2)/sqrt(x^2 + y^2)').solve('y') @@ -395,11 +409,13 @@ To TeX a maxima object do this:: + sage: from sage.interfaces.maxima import maxima sage: latex(maxima('sin(u) + sinh(v^2)')) \sinh v^2+\sin u Here's another example:: + sage: from sage.interfaces.maxima import maxima sage: g = maxima('exp(3*%i*x)/(6*%i) + exp(%i*x)/(2*%i) + c') sage: latex(g) -...{{i\,e^{3\,i\,x}}\over{6}}...-{{i\,e^{i\,x}}\over{2}}+c @@ -519,6 +535,7 @@ class Maxima(MaximaAbstract, Expect): EXAMPLES:: + sage: from sage.interfaces.maxima import maxima, Maxima sage: m = Maxima() sage: m == maxima False @@ -530,7 +547,7 @@ def __init__(self, script_subdirectory=None, logfile=None, server=None, TESTS:: - sage:: from sage.interfaces.maxima import Maxima, maxima + sage: from sage.interfaces.maxima import Maxima, maxima sage: Maxima == loads(dumps(Maxima)) True sage: maxima == loads(dumps(maxima)) @@ -606,6 +623,7 @@ def set_seed(self, seed=None): EXAMPLES:: + sage: from sage.interfaces.maxima import Maxima sage: m = Maxima() sage: m.set_seed(1) 1 @@ -624,6 +642,7 @@ def _start(self): EXAMPLES:: + sage: from sage.interfaces.maxima import Maxima sage: m = Maxima() sage: m.is_running() False @@ -648,6 +667,7 @@ def __reduce__(self): EXAMPLES:: + sage: from sage.interfaces.maxima import maxima sage: maxima.__reduce__() (, ()) """ @@ -659,6 +679,7 @@ def _sendline(self, string): EXAMPLES:: + sage: from sage.interfaces.maxima import maxima sage: maxima._sendline('t : 9;') sage: maxima.get('t') '9' @@ -680,6 +701,7 @@ def _expect_expr(self, expr=None, timeout=None): These tests indirectly show that the interface is working and catching certain errors:: + sage: from sage.interfaces.maxima import maxima sage: maxima('2+2') 4 sage: maxima('integrate(1/(x^3*(a+b*x)^(1/3)),x)') @@ -775,6 +797,7 @@ def _eval_line(self, line, allow_use_file=False, We check that errors are correctly checked:: + sage: from sage.interfaces.maxima import maxima sage: maxima._eval_line('1+1;') '2' sage: maxima._eval_line('sage0: x == x;') @@ -837,6 +860,7 @@ def _synchronize(self): EXAMPLES: This makes Maxima start a calculation:: + sage: from sage.interfaces.maxima import maxima sage: maxima._sendstr('1/1'*500) When you type this command, this synchronize command is implicitly @@ -882,6 +906,7 @@ def _batch(self, s, batchload=True): EXAMPLES:: + sage: from sage.interfaces.maxima import maxima sage: maxima._batch('10003;') '...batchload...' sage: maxima._batch('10003;',batchload=False) @@ -917,6 +942,7 @@ def _quit_string(self): EXAMPLES:: + sage: from sage.interfaces.maxima import maxima sage: maxima._quit_string() 'quit();' """ @@ -928,6 +954,7 @@ def _crash_msg(self): EXAMPLES:: + sage: from sage.interfaces.maxima import maxima sage: maxima._crash_msg() Maxima crashed -- automatically restarting. """ @@ -939,6 +966,7 @@ def _error_check(self, cmd, out): EXAMPLES:: + sage: from sage.interfaces.maxima import maxima sage: maxima._error_check("1+1;","Principal Value") Traceback (most recent call last): ... @@ -959,6 +987,7 @@ def _error_msg(self, cmd, out): EXAMPLES:: + sage: from sage.interfaces.maxima import maxima sage: maxima._error_msg("1+1;","Principal Value") Traceback (most recent call last): ... @@ -1072,6 +1101,7 @@ def _object_class(self): EXAMPLES:: + sage: from sage.interfaces.maxima import maxima sage: maxima._object_class() """ @@ -1094,6 +1124,7 @@ def _object_function_class(self): EXAMPLES:: + sage: from sage.interfaces.maxima import maxima sage: maxima._object_function_class() """ @@ -1148,7 +1179,7 @@ def __init__(self, parent, value, is_name=False, name=None): TESTS:: - sage: from sage.interfaces.maxima import MaximaElement + sage: from sage.interfaces.maxima import MaximaElement, maxima sage: loads(dumps(MaximaElement))==MaximaElement True sage: a = maxima(5) @@ -1222,6 +1253,7 @@ def __init__(self, parent, name, defn, args, latex): Unpickling a Maxima Pexpect interface gives the default interface:: + sage: from sage.interfaces.maxima import Maxima sage: m = Maxima() sage: g = m.function('x,y','x+y^9') sage: h = loads(dumps(g)) @@ -1275,7 +1307,7 @@ def __doctest_cleanup(): EXAMPLES:: - sage: from sage.interfaces.maxima import __doctest_cleanup + sage: from sage.interfaces.maxima import __doctest_cleanup, maxima sage: maxima(1) 1 sage: maxima.is_running() diff --git a/src/sage/interfaces/maxima_abstract.py b/src/sage/interfaces/maxima_abstract.py index 40ef624b155..4094c14d3c9 100644 --- a/src/sage/interfaces/maxima_abstract.py +++ b/src/sage/interfaces/maxima_abstract.py @@ -48,28 +48,28 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from itertools import islice import operator import os import re import subprocess import sys +from itertools import islice from sage.cpython.string import bytes_to_str from sage.env import DOT_SAGE, MAXIMA -from sage.interfaces.tab_completion import ExtraTabCompletion -from sage.misc.cachefunc import cached_method -from sage.misc.instancedoc import instancedoc -from sage.misc.multireplace import multiple_replace -from sage.structure.richcmp import rich_to_bool, richcmp - -from .interface import ( +from sage.interfaces.interface import ( AsciiArtString, Interface, InterfaceElement, InterfaceFunction, InterfaceFunctionElement, ) +from sage.interfaces.tab_completion import ExtraTabCompletion +from sage.misc.cachefunc import cached_method +from sage.misc.instancedoc import instancedoc +from sage.misc.multireplace import multiple_replace +from sage.structure.richcmp import rich_to_bool, richcmp + COMMANDS_CACHE = '%s/maxima_commandlist_cache.sobj' % DOT_SAGE @@ -92,12 +92,11 @@ class MaximaAbstract(ExtraTabCompletion, Interface): EXAMPLES: This class should not be instantiated directly, - but through its subclasses Maxima (Pexpect interface) - or MaximaLib (library interface):: + but through its subclass MaximaLib (which is a singleton):: - sage: m = Maxima() sage: from sage.interfaces.maxima_abstract import MaximaAbstract - sage: isinstance(m,MaximaAbstract) + sage: from sage.interfaces.maxima_lib import maxima + sage: isinstance(maxima, MaximaAbstract) True """ @@ -109,7 +108,8 @@ def __init__(self, name='maxima_abstract'): EXAMPLES:: sage: from sage.interfaces.maxima_abstract import MaximaAbstract - sage: isinstance(maxima,MaximaAbstract) + sage: from sage.interfaces.maxima_lib import maxima + sage: isinstance(maxima, MaximaAbstract) True TESTS:: @@ -120,25 +120,6 @@ def __init__(self, name='maxima_abstract'): """ Interface.__init__(self, name) - ########################################### - # System -- change directory, etc. - ########################################### - def chdir(self, dir): - r""" - Change Maxima's current working directory. - - INPUT: - - - ``dir`` -- string - - OUTPUT: none - - EXAMPLES:: - - sage: maxima.chdir('/') - """ - self.lisp('(ext::cd "%s")' % dir) - ########################################### # Interactive help ########################################### @@ -165,6 +146,7 @@ def _command_runner(self, command, s, redirect=True): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima._command_runner('describe', 'gcd') -- Function: gcd (, , , ...) ... @@ -200,6 +182,7 @@ def help(self, s): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima.help('gcd') -- Function: gcd (, , , ...) ... @@ -220,6 +203,7 @@ def example(self, s): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima.example('arrays') a[n]:=n*a[n-1] a := n a @@ -252,6 +236,7 @@ def demo(self, s): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima.demo('cf') # not tested read and interpret file: .../share/maxima/5.34.1/demo/cf.dem @@ -278,8 +263,9 @@ def completions(self, s, verbose=True): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: sorted(maxima.completions('gc', verbose=False)) - ['gcd', 'gcdex', 'gcfactor', 'gctime'] + ['gc', 'gcd', 'gcdex', 'gcfactor', 'gctime'] """ if verbose: print(s, end="") @@ -408,6 +394,7 @@ def console(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima.console() # not tested (since we can't) Maxima 5.46.0 https://maxima.sourceforge.io using Lisp ECL 21.2.1 @@ -419,6 +406,7 @@ def console(self): :: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima.interact() # not tested --> Switching to Maxima <-- maxima: 2+2 @@ -441,6 +429,7 @@ def cputime(self, t=None): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: t = maxima.cputime() sage: _ = maxima.de_solve('diff(y,x,2) + 3*x = y', ['x','y'], [1,1,1]) sage: maxima.cputime(t) # output random @@ -459,6 +448,7 @@ def version(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima.version() # random '5.41.0' """ @@ -476,6 +466,7 @@ def _assign_symbol(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima._assign_symbol() ':' sage: maxima.eval('t : 8') @@ -493,6 +484,7 @@ def _true_symbol(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima._true_symbol() 'true' sage: maxima.eval('is(2 = 2)') @@ -508,6 +500,7 @@ def _false_symbol(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima._false_symbol() 'false' sage: maxima.eval('is(2 = 4)') @@ -523,12 +516,13 @@ def _equality_symbol(self): EXAMPLES:: - sage: maxima._equality_symbol() - '=' - sage: var('x y') - (x, y) - sage: maxima(x == y) - _SAGE_VAR_x = _SAGE_VAR_y + sage: from sage.interfaces.maxima_lib import maxima + sage: maxima._equality_symbol() + '=' + sage: var('x y') + (x, y) + sage: maxima(x == y) + _SAGE_VAR_x = _SAGE_VAR_y """ return '=' @@ -540,10 +534,11 @@ def _inequality_symbol(self): EXAMPLES:: - sage: maxima._inequality_symbol() - '#' - sage: maxima((x != 1)) - _SAGE_VAR_x # 1 + sage: from sage.interfaces.maxima_lib import maxima + sage: maxima._inequality_symbol() + '#' + sage: maxima((x != 1)) + _SAGE_VAR_x # 1 """ return '#' @@ -555,6 +550,7 @@ def _function_class(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima._function_class() """ @@ -568,8 +564,9 @@ def _object_class(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima._object_class() - + """ return MaximaAbstractElement @@ -594,8 +591,9 @@ def _object_function_class(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima._object_function_class() - + """ return MaximaAbstractElementFunction @@ -622,6 +620,7 @@ def function(self, args, defn, rep=None, latex=None): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: f = maxima.function('x', 'sin(x)') sage: f(3.2) # abs tol 2e-16 -0.058374143427579909 @@ -708,6 +707,7 @@ def plot2d(self, *args): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima.plot2d('sin(x)','[x,-5,5]') # not tested sage: opts = '[gnuplot_term, ps], [gnuplot_out_file, "sin-plot.eps"]' sage: maxima.plot2d('sin(x)','[x,-5,5]',opts) # not tested @@ -738,6 +738,7 @@ def plot2d_parametric(self, r, var, trange, nticks=50, options=None): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima.plot2d_parametric(["sin(t)","cos(t)"], "t",[-3.1,3.1]) # not tested :: @@ -778,6 +779,7 @@ def plot3d(self, *args): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima.plot3d('1 + x^3 - y^2', '[x,-2,2]', '[y,-2,2]', '[grid,12,12]') # not tested sage: maxima.plot3d('sin(x)*cos(y)', '[x,-2,2]', '[y,-2,2]', '[grid,30,30]') # not tested sage: opts = '[gnuplot_term, ps], [gnuplot_out_file, "sin-plot.eps"]' @@ -811,6 +813,7 @@ def plot3d_parametric(self, r, vars, urange, vrange, options=None): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima.plot3d_parametric(["v*sin(u)","v*cos(u)","v"], ["u","v"],[-3.2,3.2],[0,3]) # not tested sage: opts = '[gnuplot_term, ps], [gnuplot_out_file, "sin-cos-plot.eps"]' sage: maxima.plot3d_parametric(["v*sin(u)","v*cos(u)","v"], ["u","v"],[-3.2,3.2],[0,3],opts) # not tested @@ -858,6 +861,7 @@ def de_solve(self, de, vars, ics=None): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima.de_solve('diff(y,x,2) + 3*x = y', ['x','y'], [1,1,1]) y = 3*x-2*%e^(x-1) sage: maxima.de_solve('diff(y,x,2) + 3*x = y', ['x','y']) @@ -902,6 +906,7 @@ def de_solve_laplace(self, de, vars, ics=None): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima.clear('x'); maxima.clear('f') sage: maxima.de_solve_laplace("diff(f(x),x,2) = 2*diff(f(x),x)-f(x)", ["x","f"], [0,1,2]) f(x) = x*%e^x+%e^x @@ -948,6 +953,7 @@ def solve_linear(self, eqns, vars): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: eqns = ["x + z = y","2*a*x - y = 2*a^2","y - 2*z = 2"] sage: vars = ["x","y","z"] sage: maxima.solve_linear(eqns, vars) @@ -978,6 +984,7 @@ def unit_quadratic_integer(self, n): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: u = maxima.unit_quadratic_integer(101); u a + 10 sage: u.parent() @@ -1028,6 +1035,7 @@ def plot_list(self, ptsx, ptsy, options=None): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: zeta_ptsx = [(pari(1/2 + i*I/10).zeta().real()).precision(1) # needs sage.libs.pari ....: for i in range(70,150)] sage: zeta_ptsy = [(pari(1/2 + i*I/10).zeta().imag()).precision(1) # needs sage.libs.pari @@ -1066,6 +1074,7 @@ def plot_multilist(self, pts_list, options=None): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: xx = [i/10.0 for i in range(-10,10)] sage: yy = [i/10.0 for i in range(-10,10)] sage: x0 = [0 for i in range(-10,10)] @@ -1107,12 +1116,9 @@ class MaximaAbstractElement(ExtraTabCompletion, InterfaceElement): Elements of this class should not be created directly. The targeted parent of a concrete inherited class should be used instead:: - sage: from sage.interfaces.maxima_lib import maxima_lib + sage: from sage.interfaces.maxima_lib import maxima sage: xp = maxima(x) sage: type(xp) - - sage: xl = maxima_lib(x) - sage: type(xl) """ _cached_repr = True @@ -1125,6 +1131,7 @@ def __str__(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: f = maxima('1/(x-1)^3'); f 1/(x-1)^3 sage: print(f) @@ -1143,6 +1150,7 @@ def __bool__(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: bool(maxima(0)) False sage: bool(maxima(1)) @@ -1170,6 +1178,7 @@ def _richcmp_(self, other, op): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: a = maxima(1); b = maxima(2) sage: a == b False @@ -1216,6 +1225,7 @@ def _sage_(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: a = maxima('sqrt(2) + 2.5'); a sqrt(2)+2.5 sage: b = a._sage_(); b @@ -1256,10 +1266,11 @@ def _sage_(self): Check conversion of Booleans (:issue:`28705`):: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima('true')._sage_(), maxima('false')._sage_() (True, False) """ - import sage.calculus.calculus as calculus + from sage.calculus import calculus return calculus.symbolic_expression_from_maxima_string(self.name(), maxima=self.parent()) @@ -1296,6 +1307,7 @@ def __complex__(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: complex(maxima('sqrt(-2)+1')) (1+1.4142135623730951j) """ @@ -1313,6 +1325,7 @@ def _complex_mpfr_field_(self, C): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: CC(maxima('1+%i')) 1.00000000000000 + 1.00000000000000*I sage: CC(maxima('2342.23482943872+234*%i')) @@ -1340,6 +1353,7 @@ def _mpfr_(self, R): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: RealField(100)(maxima('sqrt(2)+1')) 2.4142135623730950488016887242 """ @@ -1357,6 +1371,7 @@ def _complex_double_(self, C): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: CDF(maxima('sqrt(2)+1')) 2.414213562373095 """ @@ -1374,6 +1389,7 @@ def _real_double_(self, R): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: RDF(maxima('sqrt(2)+1')) 2.414213562373095 """ @@ -1387,6 +1403,7 @@ def real(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima('2 + (2/3)*%i').real() 2 """ @@ -1400,6 +1417,7 @@ def imag(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima('2 + (2/3)*%i').imag() 2/3 """ @@ -1413,10 +1431,11 @@ def numer(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: a = maxima('sqrt(2)').numer(); a 1.41421356237309... sage: type(a) - + """ return self.comma('numer') @@ -1428,6 +1447,7 @@ def str(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima('sqrt(2) + 1/3').str() 'sqrt(2)+1/3' """ @@ -1448,6 +1468,7 @@ def diff(self, var='x', n=1): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: f = maxima('x^2') sage: f.diff() 2*x @@ -1460,9 +1481,10 @@ def diff(self, var='x', n=1): :: - sage: f = maxima('x^2 + 17*y^2') + sage: from sage.interfaces.maxima_lib import maxima + sage: f = maxima('x^3 + 17*y^2') sage: f.diff('x') - 34*y*'diff(y,x,1)+2*x + 3*x^2 sage: f.diff('y') 34*y """ @@ -1516,6 +1538,7 @@ def nintegral(self, var='x', a=0, b=1, EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima('exp(-sqrt(x))').nintegral('x',0,1) (0.5284822353142306, 4.163...e-11, 231, 0) @@ -1551,6 +1574,7 @@ def integral(self, var='x', min=None, max=None): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima('x^2+1').integral() x^3/3+x sage: maxima('x^2+ 1 + y^2').integral('y') @@ -1590,6 +1614,7 @@ def __float__(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: float(maxima("3.14")) 3.14 sage: float(maxima("1.7e+17")) @@ -1610,6 +1635,7 @@ def __len__(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: v = maxima('create_list(x^i,i,0,5)') sage: len(v) 6 @@ -1629,6 +1655,7 @@ def dot(self, other): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: A = maxima('matrix ([a1],[a2])') sage: B = maxima('matrix ([b1, b2])') sage: A.dot(B) @@ -1655,6 +1682,7 @@ def __getitem__(self, i): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: v = maxima('create_list(i*x^i,i,0,5)'); v [0,x,2*x^2,3*x^3,4*x^4,5*x^5] sage: v[3] @@ -1697,6 +1725,7 @@ def __iter__(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: v = maxima('create_list(i*x^i,i,0,5)') sage: L = list(v) sage: [e._sage_() for e in L] @@ -1718,6 +1747,7 @@ def subst(self, val): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima('a^2 + 3*a + b').subst('b=2') a^2+3*a+2 sage: maxima('a^2 + 3*a + b').subst('a=17') @@ -1739,6 +1769,7 @@ def comma(self, args): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima('sqrt(2) + I').comma('numer') I+1.41421356237309... sage: maxima('sqrt(2) + I*a').comma('a=5') @@ -1759,6 +1790,7 @@ def _latex_(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima('sqrt(2) + 1/3 + asin(5)')._latex_() '\\sin^{-1}\\cdot5+\\sqrt{2}+{{1}\\over{3}}' @@ -1773,18 +1805,33 @@ def _latex_(self): """ self._check_valid() P = self.parent() - s = P._eval_line('tex(%s);' % self.name(), reformat=False) - if '$$' not in s: - raise RuntimeError("Error texing Maxima object.") - i = s.find('$$') - j = s.rfind('$$') - s = s[i+2:j] - s = multiple_replace({'\r\n': ' ', - '\\%': '', - '\\arcsin ': '\\sin^{-1} ', - '\\arccos ': '\\cos^{-1} ', - '\\arctan ': '\\tan^{-1} ', - '\\_SAGE\\_VAR\\_': ''}, s) + s = P._eval_line(f"tex({self.name()}, false);", reformat=False) + if "$$" not in s: + raise RuntimeError( + f"Error texing Maxima object {self.name()}. Expected '$$' in output, got: {s!r}" + ) + i = s.find("$$") + j = s.rfind("$$") + s = s[i + 2 : j] + s = multiple_replace( + { + "\r\n": " ", + "\\\\\\\\": "\\", + "\\\\\\": "\\", + "\\\\": "\\", + }, + s, + ) + s = multiple_replace( + { + "\\%": "", + "\\arcsin ": "\\sin^{-1} ", + "\\arccos ": "\\cos^{-1} ", + "\\arctan ": "\\tan^{-1} ", + "\\_SAGE\\_VAR\\_": "", + }, + s, + ) # Fix a maxima bug, which gives a latex representation of multiplying # two numbers as a single space. This was really bad when 2*17^(1/3) @@ -1807,6 +1854,7 @@ def _tab_completion(self, verbose=False): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: m = maxima(2) sage: 'gcd' in m._tab_completion() True @@ -1830,6 +1878,7 @@ def _matrix_(self, R): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: _ = maxima.eval("f[i,j] := i/j") sage: A = maxima('genmatrix(f,4,4)'); A matrix([1,1/2,1/3,1/4],[2,1,2/3,1/2],[3,3/2,1,3/4],[4,2,4/3,1]) @@ -1874,6 +1923,7 @@ def partial_fraction_decomposition(self, var='x'): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: f = maxima('1/((1+x)*(x-1))') sage: f.partial_fraction_decomposition('x') 1/(2*(x-1))-1/(2*(x+1)) @@ -1915,6 +1965,7 @@ def _operation(self, operation, other=None): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: f = maxima.cos(x) sage: f._operation("+", f) 2*cos(_SAGE_VAR_x) @@ -1960,6 +2011,7 @@ class MaximaAbstractElementFunction(MaximaAbstractElement): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: maxima.function('x,y','e^cos(x)') e^cos(x) """ @@ -1971,6 +2023,7 @@ def __init__(self, parent, name, defn, args, latex): TESTS:: + sage: from sage.interfaces.maxima_lib import maxima sage: from sage.interfaces.maxima_abstract import MaximaAbstractElementFunction sage: MaximaAbstractElementFunction == loads(dumps(MaximaAbstractElementFunction)) True @@ -1995,6 +2048,7 @@ def __reduce__(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: f = maxima.function('x,y','sin(x+y)') sage: f.__reduce__() (, @@ -2016,6 +2070,7 @@ def __call__(self, *args): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: f = maxima.function('x,y','sin(x+y)') sage: f(1,2) sin(3) @@ -2035,6 +2090,7 @@ def _repr_(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: f = maxima.function('x,y','sin(x+y)') sage: repr(f) # indirect doctest 'sin(x+y)' @@ -2049,6 +2105,7 @@ def _latex_(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: f = maxima.function('x,y','sin(x+y)') sage: latex(f) \mathrm{sin(x+y)} @@ -2073,6 +2130,7 @@ def arguments(self, split=True): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: f = maxima.function('x,y','sin(x+y)') sage: f.arguments() ['x', 'y'] @@ -2093,6 +2151,7 @@ def definition(self): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: f = maxima.function('x,y','sin(x+y)') sage: f.definition() 'sin(x+y)' @@ -2113,6 +2172,7 @@ def integral(self, var): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: x,y = var('x,y') sage: f = maxima.function('x','sin(x)') sage: f.integral(x) @@ -2149,6 +2209,7 @@ def _operation(self, operation, other=None): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: f = maxima.function('x,y','sin(x+y)') sage: f._operation("+", f) 2*sin(y+x) @@ -2180,6 +2241,7 @@ def reduce_load_MaximaAbstract_function(parent, defn, args, latex): EXAMPLES:: + sage: from sage.interfaces.maxima_lib import maxima sage: from sage.interfaces.maxima_abstract import reduce_load_MaximaAbstract_function sage: f = maxima.function('x,y','sin(x+y)') sage: _,args = f.__reduce__() diff --git a/src/sage/interfaces/maxima_lib.py b/src/sage/interfaces/maxima_lib.py index 95f992d97c7..169b964b72f 100644 --- a/src/sage/interfaces/maxima_lib.py +++ b/src/sage/interfaces/maxima_lib.py @@ -31,14 +31,14 @@ For this interface, Maxima is loaded into ECL which is itself loaded as a C library in Sage. Translations between Sage and Maxima objects (which are nothing but wrappers to ECL objects) is made as much as possible -directly, but falls back to the string based conversion used by the -classical Maxima Pexpect interface in case no new implementation has been made. +directly, but falls back to the string based conversion in case no new implementation +has been made. This interface is the one used for calculus by Sage and is accessible as ``maxima_calculus``:: sage: maxima_calculus - Maxima_lib + Maxima Only one instance of this interface can be instantiated, so the user should not try to instantiate another one, @@ -117,20 +117,19 @@ import sage.symbolic.expression import sage.symbolic.integration.integral from sage.env import MAXIMA_FAS, MAXIMA_SHARE -from sage.libs.ecl import EclObject, ecl_eval -from sage.misc.instancedoc import instancedoc -from sage.rings.number_field.number_field_element_base import NumberFieldElement_base -from sage.structure.element import Expression -from sage.symbolic.operators import FDerivativeOperator, add_vararg, mul_vararg -from sage.symbolic.ring import SR - -from .maxima_abstract import ( +from sage.interfaces.maxima_abstract import ( MaximaAbstract, MaximaAbstractElement, MaximaAbstractElementFunction, MaximaAbstractFunction, MaximaAbstractFunctionElement, ) +from sage.libs.ecl import EclObject, ecl_eval +from sage.misc.instancedoc import instancedoc +from sage.rings.number_field.number_field_element_base import NumberFieldElement_base +from sage.structure.element import Expression +from sage.symbolic.operators import FDerivativeOperator, add_vararg, mul_vararg +from sage.symbolic.ring import SR # We begin here by initializing Maxima in library mode # i.e. loading it into ECL @@ -164,6 +163,7 @@ ecl_eval("(initialize-runtime-globals)") ecl_eval("(setq $nolabels t))") ecl_eval("(defun add-lineinfo (x) x)") +ecl_eval(r"(defun tex-derivative (x l r) (tex (if $derivabbrev (tex-dabbrev x) (tex-d x '\\partial)) l r lop rop ))") ecl_eval('(defun principal nil (cond ($noprincipal (diverg)) ((not pcprntd) (merror "Divergent Integral"))))') ecl_eval("(remprop 'mfactorial 'grind)") # don't use ! for factorials (#11539) ecl_eval("(setf $errormsg nil)") @@ -386,7 +386,7 @@ def __init__(self): global init_code self.__init_code = init_code - MaximaAbstract.__init__(self, "maxima_lib") + MaximaAbstract.__init__(self, "maxima") self.__seq = 0 def _coerce_from_special_method(self, x): @@ -1053,7 +1053,7 @@ def _missing_assumption(self, errstr): outstr = "Computation failed since Maxima requested additional constraints; using the 'assume' command before evaluation *may* help (example of legal syntax is 'assume("\ + errstr[jj + 1:k] + ">0)', see `assume?` for more details)\n" + errstr - outstr = outstr.replace('_SAGE_VAR_', '') + outstr = outstr.replace("_SAGE_VAR_", "") raise ValueError(outstr) @@ -1180,7 +1180,7 @@ def reduce_load_MaximaLib(): sage: from sage.interfaces.maxima_lib import reduce_load_MaximaLib sage: reduce_load_MaximaLib() - Maxima_lib + Maxima """ return maxima_lib diff --git a/src/sage/interfaces/quit.py b/src/sage/interfaces/quit.py index 5a93ea6952e..5cc6d2f17e4 100644 --- a/src/sage/interfaces/quit.py +++ b/src/sage/interfaces/quit.py @@ -19,7 +19,6 @@ import sys from typing import TYPE_CHECKING -from sage.env import DOT_SAGE, HOSTNAME from sage.misc.cachefunc import cached_function if TYPE_CHECKING: @@ -146,12 +145,12 @@ def invalidate_all() -> None: EXAMPLES:: sage: # needs sage.libs.pari sage.symbolic - sage: a = maxima(2); b = gp(3) + sage: a = gap(2); b = gp(3) sage: a, b (2, 3) sage: sage.interfaces.quit.invalidate_all() sage: a - (invalid Maxima object -- The maxima session in which this object was defined is no longer running.) + (invalid Gap object -- The gap session in which this object was defined is no longer running.) sage: b (invalid PARI/GP interpreter object -- The pari session in which this object was defined is no longer running.) diff --git a/src/sage/misc/citation.pyx b/src/sage/misc/citation.pyx index 96fe00e98c4..7a75ddaf326 100644 --- a/src/sage/misc/citation.pyx +++ b/src/sage/misc/citation.pyx @@ -10,7 +10,7 @@ systems = {} systems['PARI'] = ['cypari2', 'sage.interfaces.gp'] systems['Singular'] = ['sage.interfaces.singular', '_libsingular', 'sage.libs.singular'] -systems['Maxima'] = ['sage.interfaces.maxima'] +systems['Maxima'] = ['sage.interfaces.maxima_lib'] systems['GAP'] = ['sage.interfaces.gap'] systems['Magma'] = ['sage.interfaces.magma', 'sage.interfaces.magma_free'] systems['Axiom'] = ['sage.interfaces.axiom'] diff --git a/src/sage/misc/lazy_import.pyx b/src/sage/misc/lazy_import.pyx index 426fc563396..5f048314289 100644 --- a/src/sage/misc/lazy_import.pyx +++ b/src/sage/misc/lazy_import.pyx @@ -1269,10 +1269,10 @@ def clean_namespace(namespace=None): sage: # needs sage.symbolic sage: from sage.misc.lazy_import import attributes, clean_namespace - sage: from sage.calculus.calculus import maxima as C + sage: from sage.misc.functional import CDF as C sage: attributes(C)['_as_name'] - 'maxima' - sage: attributes(C)['_namespace'] is sage.calculus.calculus.__dict__ + 'CDF' + sage: attributes(C)['_namespace'] is sage.misc.functional.__dict__ True sage: clean_namespace(globals()) sage: attributes(C)['_as_name'] diff --git a/src/sage/repl/interpreter.py b/src/sage/repl/interpreter.py index da677bbd28d..ee824db9408 100644 --- a/src/sage/repl/interpreter.py +++ b/src/sage/repl/interpreter.py @@ -560,6 +560,7 @@ def preparse_imports_from_sage(self, line): sage: # needs sage.symbolic sage: from sage.repl.interpreter import interface_shell_embed, InterfaceShellTransformer + sage: from sage.interfaces.maxima_lib import maxima sage: shell = interface_shell_embed(maxima) sage: ift = InterfaceShellTransformer(shell=shell, config=shell.config, ....: prefilter_manager=shell.prefilter_manager) @@ -568,8 +569,8 @@ def preparse_imports_from_sage(self, line): '2 + sage0 ' sage: maxima.eval('sage0') '3' - sage: ift.preparse_imports_from_sage('2 + maxima(a)') # maxima calls set_seed on startup which is why 'sage0' will becomes 'sage4' and not just 'sage1' - '2 + sage4 ' + sage: ift.preparse_imports_from_sage('2 + maxima(a)') + '2 + sage1 ' sage: ift.preparse_imports_from_sage('2 + gap(a)') '2 + gap(a)' diff --git a/src/sage/structure/sage_object.pyx b/src/sage/structure/sage_object.pyx index cecf06bdb6a..e2cb701e79c 100644 --- a/src/sage/structure/sage_object.pyx +++ b/src/sage/structure/sage_object.pyx @@ -549,14 +549,6 @@ cdef class SageObject: def parent(self): """ Return the type of ``self`` to support the coercion framework. - - EXAMPLES:: - - sage: t = log(sqrt(2) - 1) + log(sqrt(2) + 1); t # needs sage.symbolic - log(sqrt(2) + 1) + log(sqrt(2) - 1) - sage: u = t.maxima_methods() # needs sage.symbolic - sage: u.parent() # needs sage.symbolic - """ return type(self) @@ -877,18 +869,16 @@ cdef class SageObject: def _maxima_(self, G=None): if G is None: - import sage.interfaces.maxima - G = sage.interfaces.maxima.maxima + from sage.interfaces.maxima_lib import maxima + G = maxima return self._interface_(G) def _maxima_init_(self): - import sage.interfaces.maxima - I = sage.interfaces.maxima.maxima - return self._interface_init_(I) + from sage.interfaces.maxima_lib import maxima + return self._interface_init_(maxima) def _maxima_lib_(self, G=None): - from sage.interfaces.maxima_lib import maxima_lib - return self._interface_(maxima_lib) + return self._maxima_(G) def _maxima_lib_init_(self): return self._maxima_init_() diff --git a/src/sage/symbolic/assumptions.py b/src/sage/symbolic/assumptions.py index 9eef304c6fc..4b64cc4378c 100644 --- a/src/sage/symbolic/assumptions.py +++ b/src/sage/symbolic/assumptions.py @@ -34,11 +34,12 @@ Here is the list of acceptable features:: + sage: from sage.interfaces.maxima_lib import maxima sage: ", ".join(map(str, maxima("features")._sage_())) 'integer, noninteger, even, odd, rational, irrational, real, imaginary, complex, analytic, increasing, decreasing, oddfun, evenfun, posfun, constant, commutative, lassociative, rassociative, symmetric, - antisymmetric, integervalued' + antisymmetric, integervalued, one_to_one' Set positive domain using a relation:: @@ -71,10 +72,10 @@ ValueError: Assumption is inconsistent sage: forget() """ +from sage.rings.cc import CC from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.real_mpfr import RR -from sage.rings.cc import CC from sage.structure.element import Expression from sage.structure.unique_representation import UniqueRepresentation @@ -116,11 +117,12 @@ class GenericDeclaration(UniqueRepresentation): Here is the list of acceptable features:: + sage: from sage.interfaces.maxima_lib import maxima sage: ", ".join(map(str, maxima("features")._sage_())) 'integer, noninteger, even, odd, rational, irrational, real, imaginary, complex, analytic, increasing, decreasing, oddfun, evenfun, posfun, constant, commutative, lassociative, rassociative, symmetric, - antisymmetric, integervalued' + antisymmetric, integervalued, one_to_one' Test unique representation behavior:: @@ -155,11 +157,12 @@ def __init__(self, var, assumption): Here is the list of acceptable features:: + sage: from sage.interfaces.maxima_lib import maxima sage: ", ".join(map(str, maxima("features")._sage_())) 'integer, noninteger, even, odd, rational, irrational, real, imaginary, complex, analytic, increasing, decreasing, oddfun, evenfun, posfun, constant, commutative, lassociative, rassociative, - symmetric, antisymmetric, integervalued' + symmetric, antisymmetric, integervalued, one_to_one' """ self._var = var self._assumption = assumption @@ -979,6 +982,5 @@ def __exit__(self, *args, **kwds): if self.replace: forget(assumptions()) assume(self.OldAss) - else: - if len(self.Ass) > 0: - forget(self.Ass) + elif len(self.Ass) > 0: + forget(self.Ass) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 3689eb66c20..ffd13a6e03e 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -10335,23 +10335,6 @@ cdef class Expression(Expression_abc): return [self.parent()(ex) for ex in self._maxima_().partfrac(var).args()] - def maxima_methods(self): - """ - Provide easy access to maxima methods, converting the result to a - Sage expression automatically. - - EXAMPLES:: - - sage: t = log(sqrt(2) - 1) + log(sqrt(2) + 1); t - log(sqrt(2) + 1) + log(sqrt(2) - 1) - sage: res = t.maxima_methods().logcontract(); res - log((sqrt(2) + 1)*(sqrt(2) - 1)) - sage: type(res) - - """ - from sage.symbolic.maxima_wrapper import MaximaWrapper - return MaximaWrapper(self) - def rectform(self): r""" Convert this symbolic expression to rectangular form; that @@ -10437,7 +10420,7 @@ cdef class Expression(Expression_abc): sage: abs(SR(z).rectform() - (a + b*I)) # abs tol 1e-16 0.0 """ - return self.maxima_methods().rectform() + return self._maxima_().rectform()._sage_() def unhold(self, exclude=None): """ diff --git a/src/sage/symbolic/expression_conversions.py b/src/sage/symbolic/expression_conversions.py index f6dfddc4d0b..d1f4fe34a53 100644 --- a/src/sage/symbolic/expression_conversions.py +++ b/src/sage/symbolic/expression_conversions.py @@ -15,16 +15,21 @@ # https://www.gnu.org/licenses/ ############################################################################### -from operator import eq, ne, gt, lt, ge, le, mul, pow, neg, add, truediv from functools import reduce +from operator import add, eq, mul, neg, pow, truediv -from sage.misc.lazy_import import lazy_import -from sage.symbolic.ring import SR -from sage.structure.element import Expression, InfinityElement from sage.functions.log import exp -from sage.symbolic.operators import arithmetic_operators, relation_operators, FDerivativeOperator, add_vararg, mul_vararg +from sage.misc.lazy_import import lazy_import from sage.rings.number_field.number_field_element_base import NumberFieldElement_base -from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField +from sage.structure.element import Expression, InfinityElement +from sage.symbolic.operators import ( + FDerivativeOperator, + add_vararg, + arithmetic_operators, + mul_vararg, + relation_operators, +) +from sage.symbolic.ring import SR lazy_import('sage.symbolic.expression_conversion_sympy', ['SympyConverter', 'sympy_converter']) lazy_import('sage.symbolic.expression_conversion_algebraic', ['AlgebraicConverter', 'algebraic']) @@ -444,7 +449,9 @@ def pyobject(self, ex, obj): 'Pi' """ if (self.interface.name() in ['pari', 'gp'] and isinstance(obj, NumberFieldElement_base)): - from sage.rings.number_field.number_field_element_quadratic import NumberFieldElement_gaussian + from sage.rings.number_field.number_field_element_quadratic import ( + NumberFieldElement_gaussian, + ) if isinstance(obj, NumberFieldElement_gaussian): return repr(obj) try: @@ -526,19 +533,21 @@ def derivative(self, ex, operator): :: + sage: from sage.interfaces.maxima_lib import maxima sage: a = df.subs(x=exp(x)); a D[0](f)(e^x) sage: b = maxima(a); b - %at('diff('f(_SAGE_VAR__symbol0),_SAGE_VAR__symbol0,1), _SAGE_VAR__symbol0 = %e^_SAGE_VAR_x) + %at('diff('f(_SAGE_VAR__symbol0),_SAGE_VAR__symbol0,1),_SAGE_VAR__symbol0 = %e^_SAGE_VAR_x) sage: bool(b.sage() == a) True :: + sage: from sage.interfaces.maxima_lib import maxima sage: a = df.subs(x=4); a D[0](f)(4) sage: b = maxima(a); b - %at('diff('f(_SAGE_VAR__symbol0),_SAGE_VAR__symbol0,1), _SAGE_VAR__symbol0 = 4) + %at('diff('f(_SAGE_VAR__symbol0),_SAGE_VAR__symbol0,1),_SAGE_VAR__symbol0 = 4) sage: bool(b.sage() == a) True @@ -555,19 +564,21 @@ def derivative(self, ex, operator): :: + sage: from sage.interfaces.maxima_lib import maxima sage: a = f_x.subs(x=4); a D[0](f)(4, y) sage: b = maxima(a); b - %at('diff('f(_SAGE_VAR__symbol0,_SAGE_VAR_y),_SAGE_VAR__symbol0,1), _SAGE_VAR__symbol0 = 4) + %at('diff('f(_SAGE_VAR__symbol0,_SAGE_VAR_y),_SAGE_VAR__symbol0,1),_SAGE_VAR__symbol0 = 4) sage: bool(b.sage() == a) True :: + sage: from sage.interfaces.maxima_lib import maxima sage: a = f_x.subs(x=4).subs(y=8); a D[0](f)(4, 8) sage: b = maxima(a); b - %at('diff('f(_SAGE_VAR__symbol0,8),_SAGE_VAR__symbol0,1), _SAGE_VAR__symbol0 = 4) + %at('diff('f(_SAGE_VAR__symbol0,8),_SAGE_VAR__symbol0,1),_SAGE_VAR__symbol0 = 4) sage: bool(b.sage() == a) True @@ -737,7 +748,9 @@ def pyobject(self, ex, obj): result = repr(obj) else: if isinstance(obj, NumberFieldElement_base): - from sage.rings.number_field.number_field_element_quadratic import NumberFieldElement_gaussian + from sage.rings.number_field.number_field_element_quadratic import ( + NumberFieldElement_gaussian, + ) if isinstance(obj, NumberFieldElement_gaussian): return "((%s)::EXPR COMPLEX INT)" % result elif isinstance(obj, InfinityElement): @@ -1108,7 +1121,9 @@ def __init__(self, ex, base_ring=None, ring=None): super().__init__(ex, base_ring, ring) if ring is None and base_ring is not None: - from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing + from sage.rings.polynomial.laurent_polynomial_ring import ( + LaurentPolynomialRing, + ) self.ring = LaurentPolynomialRing(self.base_ring, names=self.varnames) @@ -1656,10 +1671,10 @@ class Exponentialize(ExpressionTreeWalker): # reference in the code using it, therefore avoiding rebuilding # the same canned results dictionary at each call. from sage.calculus.var import function - from sage.functions.hyperbolic import sinh, cosh, sech, csch, tanh, coth - from sage.functions.trig import sin, cos, sec, csc, tan, cot + from sage.functions.hyperbolic import cosh, coth, csch, sech, sinh, tanh + from sage.functions.trig import cos, cot, csc, sec, sin, tan from sage.rings.integer import Integer - from sage.symbolic.constants import e, I + from sage.symbolic.constants import I, e from sage.symbolic.ring import SR half = Integer(1) / Integer(2) two = Integer(2) @@ -1758,10 +1773,10 @@ def composition(self, ex, op): # return super().composition(ex, op) return op(*[self(oper) for oper in ex.operands()]) + from sage.functions.hyperbolic import cosh, sinh + from sage.functions.trig import cos, sin from sage.rings.imaginary_unit import I from sage.symbolic.ring import SR - from sage.functions.hyperbolic import sinh, cosh - from sage.functions.trig import sin, cos arg = self(ex.operands()[0])() w0, w1 = (SR.wild(u) for u in range(2)) D = arg.match(w0 + I*w1) @@ -1788,8 +1803,8 @@ class HalfAngle(ExpressionTreeWalker): """ # Code executed once at first class reference: create canned formulae. from sage.calculus.var import function - from sage.functions.hyperbolic import sinh, cosh, sech, csch, tanh, coth - from sage.functions.trig import sin, cos, sec, csc, tan, cot + from sage.functions.hyperbolic import cosh, coth, csch, sech, sinh, tanh + from sage.functions.trig import cos, cot, csc, sec, sin, tan from sage.rings.integer import Integer from sage.symbolic.ring import SR x = SR.var("x") @@ -1890,8 +1905,8 @@ def composition(self, ex, operator): sage: h() 0 """ - from sage.calculus.calculus import symbolic_sum, symbolic_product - from sage.functions.other import Function_sum, Function_prod + from sage.calculus.calculus import symbolic_product, symbolic_sum + from sage.functions.other import Function_prod, Function_sum if not operator: return self if isinstance(operator, Function_sum): diff --git a/src/sage/symbolic/maxima_wrapper.py b/src/sage/symbolic/maxima_wrapper.py deleted file mode 100644 index ca30af3efcf..00000000000 --- a/src/sage/symbolic/maxima_wrapper.py +++ /dev/null @@ -1,161 +0,0 @@ -"Access to Maxima methods" - -############################################################################### -# Sage: Open Source Mathematical Software -# Copyright (C) 2010 Burcin Erocal -# Distributed under the terms of the GNU General Public License (GPL), -# version 2 or any later version. The full text of the GPL is available at: -# https://www.gnu.org/licenses/ -############################################################################### - -from sage.structure.sage_object import SageObject -from sage.interfaces.maxima import MaximaFunctionElement -from sage.misc.instancedoc import instancedoc - - -@instancedoc -class MaximaFunctionElementWrapper(MaximaFunctionElement): - def __call__(self, *args, **kwds): - """ - Return a Sage expression instead of a Maxima pexpect interface element. - - EXAMPLES:: - - sage: t = sin(x)^2 + cos(x)^2; t - cos(x)^2 + sin(x)^2 - sage: res = t.maxima_methods().trigsimp(); res - 1 - sage: parent(res) - Symbolic Ring - """ - return super().__call__(*args, **kwds).sage() - - -class MaximaWrapper(SageObject): - def __init__(self, exp): - """ - Wrapper around Sage expressions to give access to Maxima methods. - - We convert the given expression to Maxima and convert the return value - back to a Sage expression. Tab completion and help strings of Maxima - methods also work as expected. - - EXAMPLES:: - - sage: t = log(sqrt(2) - 1) + log(sqrt(2) + 1); t - log(sqrt(2) + 1) + log(sqrt(2) - 1) - sage: u = t.maxima_methods(); u - MaximaWrapper(log(sqrt(2) + 1) + log(sqrt(2) - 1)) - sage: type(u) - - sage: u.logcontract() - log((sqrt(2) + 1)*(sqrt(2) - 1)) - sage: u.logcontract().parent() - Symbolic Ring - - TESTS: - - Test tab completions:: - - sage: import sage.interfaces.tab_completion as s - sage: u = t.maxima_methods() - sage: s.completions('u.elliptic_',globals()) - ['u.elliptic_e', 'u.elliptic_ec', 'u.elliptic_eu', 'u.elliptic_f', 'u.elliptic_kc', 'u.elliptic_pi'] - """ - self._exp = exp - self._maxima_exp = None - - def __getattr__(self, s): - """ - Direct attempts to get attributes of this wrapper to the corresponding - Maxima expression. This allows tab completion to work as expected. - - We wrap the function calls in order to convert results back to Sage. - - EXAMPLES:: - - sage: t = sin(x)^2 + cos(x)^2; t - cos(x)^2 + sin(x)^2 - sage: u = t.maxima_methods() - sage: import sage.interfaces.tab_completion as s - sage: s.completions('u.airy_',globals()) - ['u.airy_ai', 'u.airy_bi', 'u.airy_dai', 'u.airy_dbi'] - sage: type(u.airy_ai) - - sage: u.airy_ai() - airy_ai(cos(x)^2 + sin(x)^2) - """ - if self._maxima_exp is None: - self._maxima_exp = self._exp._maxima_() - if s[0] == '_': - return getattr(self._maxima_exp, s) - # add a wrapper function which converts the result back to - # a Sage expression - return MaximaFunctionElementWrapper(self._maxima_exp, s) - - def __dir__(self): - """ - Enable the tab completions. - - EXAMPLES:: - - sage: t = sin(x) + cos(x) - sage: u = t.maxima_methods() - sage: 'zeta' in u.__dir__() - True - """ - return self._maxima_()._tab_completion() - - def sage(self): - """ - Return the Sage expression this wrapper corresponds to. - - EXAMPLES:: - - sage: t = log(sqrt(2) - 1) + log(sqrt(2) + 1); t - log(sqrt(2) + 1) + log(sqrt(2) - 1) - sage: u = t.maxima_methods().sage() - sage: u is t - True - """ - return self._exp - - def _symbolic_(self, parent): - """ - EXAMPLES:: - - sage: t = log(sqrt(2) - 1) + log(sqrt(2) + 1); t - log(sqrt(2) + 1) + log(sqrt(2) - 1) - sage: u = t.maxima_methods() - sage: u._symbolic_(SR) is t - True - sage: SR(u) is t # indirect doctest - True - """ - return parent(self._exp) - - def __reduce__(self): - """ - EXAMPLES:: - - sage: t = log(sqrt(2) - 1) + log(sqrt(2) + 1); t - log(sqrt(2) + 1) + log(sqrt(2) - 1) - sage: u = t.maxima_methods(); u - MaximaWrapper(log(sqrt(2) + 1) + log(sqrt(2) - 1)) - sage: loads(dumps(u)) - MaximaWrapper(log(sqrt(2) + 1) + log(sqrt(2) - 1)) - """ - return (MaximaWrapper, (self._exp,)) - - def _repr_(self): - """ - EXAMPLES:: - - sage: t = log(sqrt(2) - 1) + log(sqrt(2) + 1); t - log(sqrt(2) + 1) + log(sqrt(2) - 1) - sage: u = t.maxima_methods(); u - MaximaWrapper(log(sqrt(2) + 1) + log(sqrt(2) - 1)) - sage: u._repr_() - 'MaximaWrapper(log(sqrt(2) + 1) + log(sqrt(2) - 1))' - """ - return "MaximaWrapper(%s)" % (self._exp) diff --git a/src/sage/symbolic/meson.build b/src/sage/symbolic/meson.build index bb8e3c1433e..041b19706fd 100644 --- a/src/sage/symbolic/meson.build +++ b/src/sage/symbolic/meson.build @@ -17,7 +17,6 @@ py.install_sources( 'function.pxd', 'function.pyx', 'function_factory.py', - 'maxima_wrapper.py', 'operators.py', 'pynac_wrap.h', 'random_tests.py', diff --git a/src/sage/symbolic/relation.py b/src/sage/symbolic/relation.py index 1471579a8df..44d15057f5a 100644 --- a/src/sage/symbolic/relation.py +++ b/src/sage/symbolic/relation.py @@ -230,6 +230,7 @@ Conversion to Maxima:: + sage: from sage.interfaces.maxima_lib import maxima sage: x = var('x') sage: eq = (x^(3/5) >= pi^2 + e^i) sage: eq._maxima_init_() @@ -239,10 +240,10 @@ sage: z.parent() is sage.calculus.calculus.maxima True sage: z = e1._maxima_(maxima) - sage: z.parent() is maxima + sage: z.parent() is sage.interfaces.maxima_lib.maxima True sage: z = maxima(e1) - sage: z.parent() is maxima + sage: z.parent() is sage.interfaces.maxima_lib.maxima True Conversion to Maple:: @@ -356,8 +357,8 @@ - William Stein (2007-07-16): added arithmetic with symbolic equations """ -from itertools import product import operator +from itertools import product def check_relation_maxima(relation): @@ -570,9 +571,9 @@ def string_to_list_of_solutions(s): sage: sage.symbolic.relation.string_to_list_of_solutions(s) [x == -1/2*a - 1/2*sqrt(a^2 - 4*b), x == -1/2*a + 1/2*sqrt(a^2 - 4*b)] """ + from sage.calculus.calculus import symbolic_expression_from_maxima_string from sage.categories.objects import Objects from sage.structure.sequence import Sequence - from sage.calculus.calculus import symbolic_expression_from_maxima_string v = symbolic_expression_from_maxima_string(s, equals_sub=True) return Sequence(v, universe=Objects(), cr_str=True) @@ -1202,6 +1203,7 @@ def solve(f, *args, explicit_solutions=None, multiplicities=None, to_poly_solve= if algorithm == 'sympy': from sympy import solve as ssolve + from sage.interfaces.sympy import sympy_set_to_list sympy_f = [s._sympy_() for s in f] sympy_vars = tuple([v._sympy_() for v in x]) @@ -1383,6 +1385,7 @@ def _solve_expression(f, x, explicit_solutions, multiplicities, if f.operator() is not operator.eq: if algorithm == 'sympy': from sympy import S, solveset + from sage.interfaces.sympy import sympy_set_to_list if isinstance(x, Expression) and x.is_symbol(): sympy_vars = (x._sympy_(),) @@ -1410,7 +1413,7 @@ def _solve_expression(f, x, explicit_solutions, multiplicities, # if so, we have a Diophantine def has_integer_assumption(v) -> bool: - from sage.symbolic.assumptions import assumptions, GenericDeclaration + from sage.symbolic.assumptions import GenericDeclaration, assumptions alist = assumptions() return any(isinstance(a, GenericDeclaration) and a.has(v) and a._assumption in ['even', 'odd', 'integer', 'integervalued'] @@ -1420,6 +1423,7 @@ def has_integer_assumption(v) -> bool: if algorithm == 'sympy': from sympy import S, solveset + from sage.interfaces.sympy import sympy_set_to_list if isinstance(x, Expression) and x.is_symbol(): sympy_vars = (x._sympy_(),) @@ -1681,12 +1685,12 @@ def solve_mod(eqns, modulus, solution_dict=False): sage: solve_mod([2*x^2+x*y, -x*y+2*y^2+x-2*y, -2*x^2+2*x*y-y^2-x-y], 1) [(0, 0)] """ + from sage.matrix.constructor import matrix + from sage.modules.free_module_element import vector from sage.rings.finite_rings.integer_mod_ring import Integers from sage.rings.integer import Integer from sage.rings.integer_ring import crt_basis from sage.structure.element import Expression - from sage.modules.free_module_element import vector - from sage.matrix.constructor import matrix if not isinstance(eqns, (list, tuple)): eqns = [eqns] @@ -1793,9 +1797,9 @@ def _solve_mod_prime_power(eqns, p, m, vars): [1, 21, 71, 1179, 2429, 47571, 1296179, 8703821, 26452429, 526452429, 13241296179, 19473547571, 2263241296179] """ + from sage.modules.free_module_element import vector from sage.rings.finite_rings.integer_mod_ring import Integers from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - from sage.modules.free_module_element import vector mrunning = 1 ans = [] diff --git a/src/sage/tests/benchmark.py b/src/sage/tests/benchmark.py index 7f5962df896..08530f32d06 100644 --- a/src/sage/tests/benchmark.py +++ b/src/sage/tests/benchmark.py @@ -27,7 +27,7 @@ from sage.interfaces.magma import Magma, magma from sage.interfaces.maple import maple from sage.interfaces.mathematica import mathematica -from sage.interfaces.maxima import maxima +from sage.interfaces.maxima_lib import maxima from sage.interfaces.singular import singular from sage.libs.gap.libgap import libgap from sage.libs.pari import pari