Ticket #7377: sagemax.py

File sagemax.py, 8.6 KB (added by nbruin, 10 years ago)

example package for how to accomplish said interface

Line 
1r"""
2Conversion between Sage Symbolic Ring and Maxima via ECL library interface
3"""
4###############################################################################
5#   Sage: Open Source Mathematical Software
6#       Copyright (C) 2009 Nils Bruin <nbruin@sfu.ca>
7#  Distributed under the terms of the GNU General Public License (GPL),
8#  version 2 or any later version.  The full text of the GPL is available at:
9#                  http://www.gnu.org/licenses/
10###############################################################################
11
12
13from sage.libs.ecl import *
14import sage.symbolic.expression
15from sage.symbolic.ring import is_SymbolicVariable
16from sage.symbolic.ring import SR
17
18ecl_eval("(require 'maxima)")
19ecl_eval("(in-package :maxima)")
20
21car=EclObject("car")
22cdr=EclObject("cdr")
23caar=EclObject("caar")
24cadadr=EclObject("cadadr")
25meval=EclObject("meval")
26NIL=EclObject("NIL")
27ratdisrep=EclObject("ratdisrep")
28
29#first we define the dictionary in text form because that is easier to edit
30
31op_sage_to_max = {
32    sage.symbolic.expression.operator.abs : "MABS",
33    sage.symbolic.expression.operator.add : "MPLUS",
34    sage.symbolic.expression.operator.div : "MQUOTIENT",
35    sage.symbolic.expression.operator.eq : "MEQUAL",
36    sage.symbolic.expression.operator.ge : "MGEQP",
37    sage.symbolic.expression.operator.gt : "MGREATERP",
38    sage.symbolic.expression.operator.le : "MLEQP",
39    sage.symbolic.expression.operator.lt : "MLESSP",
40    sage.symbolic.expression.operator.mul : "MTIMES",
41    sage.symbolic.expression.operator.ne : "MNOTEQUAL",
42    sage.symbolic.expression.operator.neg : "MMINUS",
43    sage.symbolic.expression.operator.pow : "MEXPT",
44    sage.symbolic.expression.operator.or_ : "MOR",
45    sage.symbolic.expression.operator.and_ : "MAND",
46    sage.functions.trig.acos : "%ACOS",
47    sage.functions.trig.acot : "%ACOT",
48    sage.functions.trig.acsc : "%ACSC",
49    sage.functions.trig.asec : "%ASEC",
50    sage.functions.trig.asin : "%ASIN",
51    sage.functions.trig.atan : "%ATAN",
52    sage.functions.trig.cos : "%COS",
53    sage.functions.trig.cot : "%COT",
54    sage.functions.trig.csc : "%CSC",
55    sage.functions.trig.sec : "%SEC",
56    sage.functions.trig.sin : "%SIN",
57    sage.functions.trig.tan : "%TAN",
58    sage.functions.log.exp : "%EXP",
59    sage.functions.log.ln : "%LOG",
60    sage.functions.log.log : "%LOG",
61    sage.functions.other.factorial : "MFACTORIAL",
62    sage.functions.other.erf : "%ERF",
63    sage.calculus.calculus._limit : "$LIMIT",
64    sage.calculus.calculus.dummy_diff : "$DIFF",
65    sage.calculus.calculus._integrate : "$INTEGRATE"
66}
67#we compile the dictionary
68op_sage_to_max = dict([(k,EclObject(op_sage_to_max[k])) for k in op_sage_to_max])
69
70#and also construct the dictionary in the other direction
71op_max_to_sage = dict([(op_sage_to_max[k],k) for k in op_sage_to_max])
72
73def add_vararg(*args):
74    S=0
75    for a in args:
76        S=S+a
77    return S
78
79def mul_vararg(*args):
80    P=1
81    for a in args:
82        P=P*a
83    return P
84
85def sage_rat(x,y):
86    return x/y
87
88op_max_to_sage[EclObject("MPLUS")]=add_vararg
89op_max_to_sage[EclObject("MTIMES")]=mul_vararg
90op_max_to_sage[EclObject("RAT")]=sage_rat
91
92sym_sage_to_max={}
93sym_max_to_sage={}
94
95def symbol_factory(packager,prefix):
96    r"""
97    Produce a symbol generator
98   
99    EXAMPLES::
100
101        sage: from sagemax import *
102        ;;; Loading #P"/usr/local/sage/4.1.2/local/lib/ecl/maxima.fas"
103        sage: f=symbol_factory(SR,"myname")
104        sage: [f.next() for i in [1..10]] 
105
106        [myname1,
107         myname2,
108         myname3,
109         myname4,
110         myname5,
111         myname6,
112         myname7,
113         myname8,
114         myname9,
115         myname10]
116   
117    """
118    i=1
119    while True:
120        yield packager(prefix+str(i))
121        i +=1
122
123def mrat_to_sage(expr):
124    r"""
125    Convert a maxima MRAT expression to Sage SR
126   
127    Maxima has an optimised representation for multivariate rational expressions.
128    The easiest way to translate those to SR is by first asking maxima to give
129    the generic representation of the object. That is what RATDISREP does in
130    maxima.
131    """
132    return max_to_sage(meval(EclObject([[ratdisrep],expr])))
133
134special_max_to_sage={
135    EclObject("MRAT") : mrat_to_sage
136}
137
138maxop=symbol_factory(EclObject,"SAGE-OP-")
139maxsym=symbol_factory(EclObject,"SAGE-SYM-")
140sageop=symbol_factory(sage.calculus.calculus.function,"maxima_op_")
141sagesym=symbol_factory(sage.calculus.calculus.var,"maxima_sym_")
142
143def max_read(s):
144    r"""
145    Maxima's reader
146   
147    Convert a string into a maxima object via maxima's reader. Only use for
148    development purposes, since the macro used in this routine suffers from
149    performance loss with heavy usage. Does give good insight into internal
150    representation of maxima objects, though.
151   
152    EXAMPLES::
153   
154        sage: from sagemax import *
155        ;;; Loading #P"/usr/local/sage/4.1.2/local/lib/ecl/maxima.fas"
156        sage: max_read("integral(sin(x),x)")
157        <ECL: (($INTEGRAL) ((%SIN) $X) $X)>
158
159    """
160    return cadadr(EclObject("#$%s$"%s))
161
162def pyobject_to_max(obj):
163    r"""
164    Translate a python object into a maxima object
165   
166    Mainly just a wrapper around EclObject, but needs to be in place because
167    some objects might be translated better into maxima than just into lisp
168    (think vectors and matrices).
169    """
170    return EclObject(obj)
171
172def sage_to_max(expr):
173    r"""
174    Convert a symbolic ring expression to maxima
175   
176    EXAMPLES::
177
178        sage: from sagemax import *
179        ;;; Loading #P"/usr/local/sage/4.1.2/local/lib/ecl/maxima.fas"
180        sage: from sage.calculus.calculus import _integrate
181        sage: I=_integrate(cos(x),x)
182        sage: sage_to_max(I)
183        <ECL: (($INTEGRATE) ((%COS) SAGE-SYM-1) SAGE-SYM-1)>
184        sage: meval(sage_to_max(I))
185        <ECL: ((%SIN SIMP) SAGE-SYM-1)>
186        sage: max_to_sage(meval(sage_to_max(I)))
187        sin(x)
188       
189    This process has defined a mapping from the sage SR element x to maxima::
190   
191        sage: sym_sage_to_max[x]
192        <ECL: SAGE-SYM-1>
193
194    And this mapping exists in the other direction too (this is why EclObjects
195    should be quickly hashable)::
196   
197        sage: sym_max_to_sage[sym_sage_to_max[x]]
198        x
199
200    Expressions that do not have a special meaning get translated relatively
201    robustly. For instance, formal derivatives have not been implemented yet::
202   
203        sage: f=SFunction('f')
204        sage: L=sage_to_max(derivative(f(x),x))
205        sage: L
206        <ECL: ((SAGE-OP-2) SAGE-SYM-1)>
207
208    As you can see, the nature of the derivative is not translated at all.
209    However, the reverse mapping unpacks that again::
210   
211        sage: max_to_sage(L)
212        D[0](f)(x)
213    """
214   
215    global op_sage_to_max, op_max_to_sage
216    global sym_sage_to_max, sym_max_to_sage
217    op = expr.operator()
218    if op:
219        if not (op in op_sage_to_max):
220            op_max=maxop.next()
221            op_sage_to_max[op]=op_max
222            op_max_to_sage[op_max]=op
223        return EclObject(([op_sage_to_max[op]], [sage_to_max(o) for o in expr.operands()]))
224    elif is_SymbolicVariable(expr):
225        if not expr in sym_sage_to_max:
226            sym_max=maxsym.next()
227            sym_sage_to_max[expr]=sym_max
228            sym_max_to_sage[sym_max]=expr
229        return sym_sage_to_max[expr]
230    else:
231        return pyobject_to_max(expr.pyobject())
232
233def max_to_sage(expr):
234    r"""
235    Convert a maxima expression to sage symbolic ring
236   
237    EXAMPLES::
238
239        sage: from sagemax import *
240        ;;; Loading #P"/usr/local/sage/4.1.2/local/lib/ecl/maxima.fas"
241        sage: from sage.calculus.calculus import _integrate
242        sage: I=_integrate(cos(x),x)
243        sage: sage_to_max(I)
244        <ECL: (($INTEGRATE) ((%COS) SAGE-SYM-1) SAGE-SYM-1)>
245        sage: meval(sage_to_max(I))
246        <ECL: ((%SIN SIMP) SAGE-SYM-1)>
247        sage: max_to_sage(meval(sage_to_max(I)))
248        sin(x)
249   
250       
251    """
252    global op_sage_to_max, op_max_to_sage
253    global sym_sage_to_max, sym_max_to_sage
254    if expr.consp():
255        op_max=caar(expr)
256        if op_max in special_max_to_sage:
257            return special_max_to_sage[op_max](expr)
258        if not(op_max in op_max_to_sage):
259            op=sageop.next()
260            op_max_to_sage[op_max]=op
261            op_sage_to_max[op]=op_max
262        op=op_max_to_sage[op_max]
263        max_args=cdr(expr)
264        args=[]
265        while not(max_args.nullp()):
266            args.append(max_to_sage(car(max_args)))
267            max_args=cdr(max_args)
268        return op(*args)
269    elif expr.symbolp():
270        if not(expr in sym_max_to_sage):
271            sym=sagesym.next()
272            sym_max_to_sage[expr]=sym
273            sym_sage_to_max[sym]=expr
274        sym=sym_max_to_sage[expr]
275        return sym
276    else:
277        return expr.python()