Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/interfaces/maple.py
4036 views
1
r"""
2
Interface to Maple
3
4
AUTHORS:
5
6
- William Stein (2005): maple interface
7
8
- Gregg Musiker (2006-02-02): tutorial
9
10
- William Stein (2006-03-05): added tab completion, e.g., maple.[tab],
11
and help, e.g, maple.sin?.
12
13
You must have the optional commercial Maple interpreter installed
14
and available as the command ``maple`` in your PATH in
15
order to use this interface. You do not have to install any
16
optional Sage packages.
17
18
Type ``maple.[tab]`` for a list of all the functions
19
available from your Maple install. Type
20
``maple.[tab]?`` for Maple's help about a given
21
function. Type ``maple(...)`` to create a new Maple
22
object, and ``maple.eval(...)`` to run a string using
23
Maple (and get the result back as a string).
24
25
EXAMPLES::
26
27
sage: maple('3 * 5') # optional - maple
28
15
29
sage: maple.eval('ifactor(2005)') # optional - maple
30
'"(5)*"(401)'
31
sage: maple.ifactor(2005) # optional - maple
32
"(5)*"(401)
33
sage: maple.fsolve('x^2=cos(x)+4', 'x=0..5') # optional - maple
34
1.914020619
35
sage: maple.factor('x^5 - y^5') # optional - maple
36
(x-y)*(x^4+x^3*y+x^2*y^2+x*y^3+y^4)
37
38
If the string "error" (case insensitive) occurs in the output of
39
anything from Maple, a RuntimeError exception is raised.
40
41
Tutorial
42
--------
43
44
AUTHORS:
45
46
- Gregg Musiker (2006-02-02): initial version.
47
48
This tutorial is based on the Maple Tutorial for number theory from
49
http://www.math.mun.ca/~drideout/m3370/numtheory.html.
50
51
There are several ways to use the Maple Interface in Sage. We will
52
discuss two of those ways in this tutorial.
53
54
55
#. If you have a maple expression such as
56
57
::
58
59
factor( (x^5-1));
60
61
We can write that in sage as
62
63
::
64
65
sage: maple('factor(x^5-1)') # optional - maple
66
(x-1)*(x^4+x^3+x^2+x+1)
67
68
Notice, there is no need to use a semicolon.
69
70
#. Since Sage is written in Python, we can also import maple
71
commands and write our scripts in a Pythonic way. For example,
72
``factor()`` is a maple command, so we can also factor
73
in Sage using
74
75
::
76
77
sage: maple('(x^5-1)').factor() # optional - maple
78
(x-1)*(x^4+x^3+x^2+x+1)
79
80
where ``expression.command()`` means the same thing as
81
``command(expression)`` in Maple. We will use this
82
second type of syntax whenever possible, resorting to the first
83
when needed.
84
85
::
86
87
sage: maple('(x^12-1)/(x-1)').simplify() # optional - maple
88
x^11+x^10+x^9+x^8+x^7+x^6+x^5+x^4+x^3+x^2+x+1
89
90
91
The normal command will always reduce a rational function to the
92
lowest terms. The factor command will factor a polynomial with
93
rational coefficients into irreducible factors over the ring of
94
integers. So for example,
95
96
::
97
98
sage: maple('(x^12-1)').factor( ) # optional - maple
99
(x-1)*(x+1)*(x^2+x+1)*(x^2-x+1)*(x^2+1)*(x^4-x^2+1)
100
101
::
102
103
sage: maple('(x^28-1)').factor( ) # optional - maple
104
(x-1)*(x^6+x^5+x^4+x^3+x^2+x+1)*(x+1)*(1-x+x^2-x^3+x^4-x^5+x^6)*(x^2+1)*(x^12-x^10+x^8-x^6+x^4-x^2+1)
105
106
Another important feature of maple is its online help. We can
107
access this through sage as well. After reading the description of
108
the command, you can press q to immediately get back to your
109
original prompt.
110
111
Incidentally you can always get into a maple console by the
112
command
113
114
::
115
116
sage: maple.console() # not tested
117
sage: !maple # not tested
118
119
Note that the above two commands are slightly different, and the
120
first is preferred.
121
122
For example, for help on the maple command fibonacci, we type
123
124
::
125
126
sage: maple.help('fibonacci') # not tested, since it uses a pager
127
128
We see there are two choices. Type
129
130
::
131
132
sage: maple.help('combinat, fibonacci') # not tested, since it uses a pager
133
134
We now see how the Maple command fibonacci works under the
135
combinatorics package. Try typing in
136
137
::
138
139
sage: maple.fibonacci(10) # optional - maple
140
fibonacci(10)
141
142
You will get fibonacci(10) as output since Maple has not loaded the
143
combinatorics package yet. To rectify this type
144
145
::
146
147
sage: maple('combinat[fibonacci]')(10) # optional - maple
148
55
149
150
instead.
151
152
If you want to load the combinatorics package for future
153
calculations, in Sage this can be done as
154
155
::
156
157
sage: maple.with_package('combinat') # optional - maple
158
159
or
160
161
::
162
163
sage: maple.load('combinat') # optional - maple
164
165
Now if we type ``maple.fibonacci(10)``, we get the
166
correct output::
167
168
sage: maple.fibonacci(10) # optional - maple
169
55
170
171
Some common maple packages include ``combinat``,
172
``linalg``, and ``numtheory``. To produce
173
the first 19 Fibonacci numbers, use the sequence command.
174
175
::
176
177
sage: maple('seq(fibonacci(i),i=1..19)') # optional - maple
178
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584,
179
4181
180
181
Two other useful Maple commands are ifactor and isprime. For
182
example
183
184
::
185
186
sage: maple.isprime(maple.fibonacci(27)) # optional - maple
187
false
188
sage: maple.ifactor(maple.fibonacci(27)) # optional - maple
189
"(2)*"(17)*"(53)*"(109)
190
191
Note that the isprime function that is included with Sage (which
192
uses PARI) is better than the Maple one (it is faster and gives a
193
provably correct answer, whereas Maple is sometimes wrong).
194
195
::
196
197
sage: alpha = maple('(1+sqrt(5))/2') # optional - maple
198
sage: beta = maple('(1-sqrt(5))/2') # optional - maple
199
sage: f19 = alpha^19 - beta^19/maple('sqrt(5)') # optional - maple
200
sage: f19 # optional - maple
201
(1/2+1/2*5^(1/2))^19-1/5*(1/2-1/2*5^(1/2))^19*5^(1/2)
202
sage: f19.simplify() # somewhat randomly ordered output; optional - maple
203
6765+5778/5*5^(1/2)
204
205
Let's say we want to write a maple program now that squares a
206
number if it is positive and cubes it if it is negative. In maple,
207
that would look like
208
209
::
210
211
mysqcu := proc(x)
212
if x > 0 then x^2;
213
else x^3; fi;
214
end;
215
216
In Sage, we write
217
218
::
219
220
sage: mysqcu = maple('proc(x) if x > 0 then x^2 else x^3 fi end') # optional - maple
221
sage: mysqcu(5) # optional - maple
222
25
223
sage: mysqcu(-5) # optional - maple
224
-125
225
226
More complicated programs should be put in a separate file and
227
loaded.
228
"""
229
230
#############################################################################
231
# Copyright (C) 2005 William Stein <[email protected]>
232
#
233
# Distributed under the terms of the GNU General Public License (GPL)
234
#
235
# http://www.gnu.org/licenses/
236
#############################################################################
237
238
from __future__ import with_statement
239
240
import os
241
242
from expect import Expect, ExpectElement, ExpectFunction, FunctionElement, gc_disabled
243
244
import pexpect
245
246
from sage.misc.misc import verbose, DOT_SAGE
247
from sage.misc.pager import pager
248
249
COMMANDS_CACHE = '%s/maple_commandlist_cache.sobj'%DOT_SAGE
250
251
class Maple(Expect):
252
"""
253
Interface to the Maple interpreter.
254
255
Type ``maple.[tab]`` for a list of all the functions
256
available from your Maple install. Type
257
``maple.[tab]?`` for Maple's help about a given
258
function. Type ``maple(...)`` to create a new Maple
259
object, and ``maple.eval(...)`` to run a string using
260
Maple (and get the result back as a string).
261
"""
262
def __init__(self, maxread=100, script_subdirectory="", server=None, server_tmpdir=None, logfile=None):
263
"""
264
Create an instance of the Maple interpreter.
265
266
EXAMPLES::
267
268
sage: maple == loads(dumps(maple))
269
True
270
"""
271
Expect.__init__(self,
272
name = 'maple',
273
prompt = '#-->',
274
command = "maple -t",
275
maxread = maxread,
276
script_subdirectory = script_subdirectory,
277
restart_on_ctrlc = False,
278
server = server,
279
server_tmpdir = server_tmpdir,
280
verbose_start = False,
281
logfile = logfile,
282
eval_using_file_cutoff=1) # very important that this is 1
283
# It's very important to use file i/o for everything,
284
# since maple stupid command line interface always
285
# dumps you into the editor when an error occurs,
286
# and I can find no way to turn it off!!
287
288
def _function_class(self):
289
"""
290
EXAMPLES::
291
292
sage: maple._function_class()
293
<class 'sage.interfaces.maple.MapleFunction'>
294
295
::
296
297
sage: type(maple.diff)
298
<class 'sage.interfaces.maple.MapleFunction'>
299
"""
300
return MapleFunction
301
302
def _keyboard_interrupt(self):
303
print "Interrupting %s..."%self
304
self._expect.sendline(chr(3)) # send ctrl-c
305
self._expect.expect(self._prompt)
306
self._expect.expect(self._prompt)
307
raise RuntimeError, "Ctrl-c pressed while running %s"%self
308
309
def __reduce__(self):
310
"""
311
EXAMPLES::
312
313
sage: maple.__reduce__()
314
(<function reduce_load_Maple at 0x...>, ())
315
sage: f, args = _
316
sage: f(*args)
317
Maple
318
"""
319
return reduce_load_Maple, tuple([])
320
321
def _read_in_file_command(self, filename):
322
r"""
323
Returns the string used to read filename into Maple.
324
325
EXAMPLES::
326
327
sage: maple._read_in_file_command('test')
328
'read "test"'
329
330
::
331
332
sage: filename = tmp_filename()
333
sage: f = open(filename, 'w')
334
sage: f.write('xx := 22;\n')
335
sage: f.close()
336
sage: maple.read(filename) # optional - maple
337
sage: maple.get('xx').strip() # optional - maple
338
'22'
339
"""
340
return 'read "%s"'%filename
341
342
def _quit_string(self):
343
"""
344
EXAMPLES::
345
346
sage: maple._quit_string()
347
'quit'
348
349
::
350
351
sage: m = Maple()
352
sage: a = m(2) # optional - maple
353
sage: m.is_running() # optional - maple
354
True
355
sage: m.quit() # optional - maple
356
sage: m.is_running() # optional - maple
357
False
358
"""
359
return 'quit'
360
361
def _install_hints(self):
362
"""
363
Hints for installing Maple on your computer.
364
365
AUTHORS:
366
367
- William Stein and Justin Walker (2006-02-12).
368
369
EXAMPLES::
370
371
sage: print maple._install_hints()
372
In order...
373
"""
374
return """
375
376
In order to use the Maple interface you need to have Maple installed
377
and have a script in your PATH called "maple" that runs the
378
command-line version of Maple. Alternatively, you could use a remote
379
connection to a server running Maple; for hints, type
380
print maple._install_hints_ssh()
381
382
(1) You might have to buy Maple (http://webstore.maplesoft.com/).
383
384
(2) * LINUX: The maple script comes standard with your Maple install.
385
386
* APPLE OS X:
387
(a) create a file called maple (in your PATH), with the following contents:
388
#!/bin/sh
389
/Library/Frameworks/Maple.framework/Versions/Current/bin/maple $@
390
(b) Save the file.
391
(c) Make the file executable.
392
chmod +x maple
393
394
* WINDOWS:
395
You must install Maple-for-Linux into the VMware machine (sorry, that's
396
the only way at present).
397
"""
398
399
def expect(self):
400
"""
401
Returns the pexpect object for this Maple session.
402
403
EXAMPLES::
404
405
sage: m = Maple()
406
sage: m.expect() is None
407
True
408
sage: m._start() # optional - maple
409
sage: m.expect() # optional - maple
410
<pexpect.spawn instance at 0x...>
411
sage: m.quit() # optional - maple
412
"""
413
return self._expect
414
415
def console(self):
416
"""
417
Spawn a new Maple command-line session.
418
419
EXAMPLES::
420
421
sage: maple.console() # not tested
422
|^/| Maple 11 (IBM INTEL LINUX)
423
._|\| |/|_. Copyright (c) Maplesoft, a division of Waterloo Maple Inc. 2007
424
\ MAPLE / All rights reserved. Maple is a trademark of
425
<____ ____> Waterloo Maple Inc.
426
| Type ? for help.
427
>
428
"""
429
maple_console()
430
431
## def killall(self):
432
## """
433
## Kill all running instances of the maple interpreter
434
## on this system.
435
436
## TODO: When Sage exits it doesn't correctly by default kill
437
## all running Maple interpreters, for some strange reason.
438
## Calling this function uses the kill and pidof operating system
439
## programs to find all instances of cmaple and kill them.
440
## """
441
## import os
442
## self._expect = None
443
## while True:
444
## pid = os.popen("pidof cmaple").read()[:-1]
445
## if len(pid) > 0:
446
## os.system('kill -9 %s'%pid)
447
## else:
448
## break
449
450
def completions(self, s):
451
"""
452
Return all commands that complete the command starting with the
453
string s. This is like typing s[Ctrl-T] in the maple interpreter.
454
455
EXAMPLES::
456
457
sage: c = maple.completions('di') # optional - maple
458
sage: 'divide' in c # optional - maple
459
True
460
"""
461
bs = chr(8)*len(s)
462
if self._expect is None:
463
self._start()
464
E = self._expect
465
E.sendline('%s%s%s'%(s,chr(20),bs))
466
t = E.timeout
467
E.timeout=0.3 # since some things have no completion
468
try:
469
E.expect('----')
470
except pexpect.TIMEOUT:
471
E.timeout = t
472
return []
473
E.timeout = t
474
v = E.before
475
E.expect(self._prompt)
476
E.expect(self._prompt)
477
return v.split()[2:]
478
479
def _commands(self):
480
"""
481
Return list of all commands defined in Maple.
482
483
EXAMPLES::
484
485
sage: c = maple._commands() # optional - maple
486
sage: len(c) > 100 # optional - maple
487
True
488
sage: 'dilog' in c # optional - maple
489
True
490
"""
491
try:
492
v = sum([self.completions(chr(65+n)) for n in range(26)], []) + \
493
sum([self.completions(chr(97+n)) for n in range(26)], [])
494
except RuntimeError:
495
print "\n"*3
496
print "*"*70
497
print "WARNING: You do not have a working version of Maple installed!"
498
print "*"*70
499
v = []
500
v.sort()
501
return v
502
503
def trait_names(self, verbose=True, use_disk_cache=True):
504
"""
505
Returns a list of all the commands defined in Maple and optionally
506
(per default) store them to disk.
507
508
EXAMPLES::
509
510
sage: c = maple.trait_names(use_disk_cache=False, verbose=False) # optional - maple
511
sage: len(c) > 100 # optional - maple
512
True
513
sage: 'dilog' in c # optional - maple
514
True
515
"""
516
try:
517
return self.__trait_names
518
except AttributeError:
519
import sage.misc.persist
520
if use_disk_cache:
521
try:
522
self.__trait_names = sage.misc.persist.load(COMMANDS_CACHE)
523
return self.__trait_names
524
except IOError:
525
pass
526
if verbose:
527
print "\nBuilding Maple command completion list (this takes"
528
print "a few seconds only the first time you do it)."
529
print "To force rebuild later, delete %s."%COMMANDS_CACHE
530
v = self._commands()
531
self.__trait_names = v
532
if len(v) > 200:
533
# Maple is actually installed.
534
sage.misc.persist.save(v, COMMANDS_CACHE)
535
return v
536
537
def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if_needed=False):
538
"""
539
EXAMPLES::
540
541
sage: maple._eval_line('2+2') # optional - maple
542
'4'
543
"""
544
line += ';'
545
with gc_disabled():
546
z = Expect._eval_line(self, line, allow_use_file=allow_use_file,
547
wait_for_prompt=wait_for_prompt).replace('\\\n','').strip()
548
if z.lower().find("error") != -1:
549
# The following was very tricky to figure out.
550
# When an error occurs using Maple, unfortunately,
551
# Maple also dumps one into the line where the
552
# error occurred with that line copied in. This
553
# totally messes up the pexpect interface. However,
554
# I think the following few lines successfully
555
# "clear things out", i.e., delete the text from
556
# the edit buffer and get a clean prompt.
557
e = self.expect()
558
e.sendline('%s__sage__;'%(chr(8)*len(line)))
559
e.expect('__sage__;')
560
e.expect(self._prompt)
561
raise RuntimeError, "An error occurred running a Maple command:\nINPUT:\n%s\nOUTPUT:\n%s"%(line, z)
562
return z
563
564
def cputime(self, t=None):
565
r"""
566
Returns the amount of CPU time that the Maple session has used. If
567
``t`` is not None, then it returns the difference
568
between the current CPU time and ``t``.
569
570
EXAMPLES::
571
572
sage: t = maple.cputime() # optional - maple
573
sage: t # random; optional - maple
574
0.02
575
sage: x = maple('x') # optional - maple
576
sage: maple.diff(x^2, x) # optional - maple
577
2*x
578
sage: maple.cputime(t) # random; optional - maple
579
0.0
580
"""
581
if t is None:
582
return float(self('time()'))
583
else:
584
return float(self('time() - %s'%float(t)))
585
586
def set(self, var, value):
587
"""
588
Set the variable var to the given value.
589
590
EXAMPLES::
591
592
sage: maple.set('xx', '2') # optional - maple
593
sage: maple.get('xx') # optional - maple
594
'2'
595
"""
596
cmd = '%s:=%s:'%(var,value)
597
out = self.eval(cmd)
598
if out.find("error") != -1:
599
raise TypeError, "Error executing code in Maple\nCODE:\n\t%s\nMaple ERROR:\n\t%s"%(cmd, out)
600
601
def get(self, var):
602
"""
603
Get the value of the variable var.
604
605
EXAMPLES::
606
607
sage: maple.set('xx', '2') # optional - maple
608
sage: maple.get('xx') # optional - maple
609
'2'
610
"""
611
s = self.eval('printf("%%q",%s)'%var)
612
return s
613
614
def _object_class(self):
615
"""
616
Returns the class of MapleElements.
617
618
EXAMPLES::
619
620
sage: maple._object_class()
621
<class 'sage.interfaces.maple.MapleElement'>
622
623
::
624
625
sage: m = maple(2) # optional - maple
626
sage: type(m) # optional - maple
627
<class 'sage.interfaces.maple.MapleElement'>
628
"""
629
return MapleElement
630
631
def _function_element_class(self):
632
"""
633
Returns the MapleFunctionElement class.
634
635
EXAMPLES::
636
637
sage: maple._function_element_class()
638
<class 'sage.interfaces.maple.MapleFunctionElement'>
639
640
::
641
642
sage: two = maple(2) # optional - maple
643
sage: type(two.gcd) # optional - maple
644
<class 'sage.interfaces.maple.MapleFunctionElement'>
645
"""
646
return MapleFunctionElement
647
648
def _equality_symbol(self):
649
"""
650
Returns the symbol used for equality testing in Maple.
651
652
EXAMPLES::
653
654
sage: maple._equality_symbol()
655
'='
656
657
sage: maple(2) == maple(2) # optional -- requires maple
658
True
659
"""
660
return '='
661
662
def _true_symbol(self):
663
"""
664
Returns the symbol used for truth in Maple.
665
666
EXAMPLES::
667
668
sage: maple._true_symbol()
669
'true'
670
671
::
672
673
sage: maple(2) == maple(2) # optional - maple
674
True
675
"""
676
return 'true'
677
678
def _assign_symbol(self):
679
"""
680
Returns the symbol used for assignment in Maple.
681
682
EXAMPLES::
683
684
sage: maple._assign_symbol()
685
':='
686
"""
687
return ":="
688
689
def _source(self, s):
690
"""
691
Tries to return the source code of a Maple function str as a
692
string.
693
694
EXAMPLES::
695
696
sage: print maple._source('curry').strip() # optional - maple
697
p -> subs('_X' = args[2 .. nargs], () -> p(_X, args))
698
sage: maple._source('ZZZ') # optional - maple
699
Traceback (most recent call last):
700
...
701
Exception: no source code could be found
702
"""
703
cmd = 'echo "interface(verboseproc=2): print(%s);" | maple -q'%s
704
src = os.popen(cmd).read()
705
if src.strip() == s:
706
raise Exception, "no source code could be found"
707
else:
708
return src
709
710
def source(self, s):
711
"""
712
Display the Maple source (if possible) about s. This is the same as
713
returning the output produced by the following Maple commands:
714
715
interface(verboseproc=2): print(s)
716
717
INPUT:
718
719
720
- ``s`` - a string representing the function whose
721
source code you want
722
723
724
EXAMPLES::
725
726
sage: maple.source('curry') #not tested
727
p -> subs('_X' = args[2 .. nargs], () -> p(_X, args))
728
"""
729
try:
730
pager()(self._source(s))
731
except Exception:
732
pager()('No source code could be found.')
733
734
def _help(self, str):
735
r"""
736
Returns the Maple help on ``str``.
737
738
EXAMPLES::
739
740
sage: maple._help('gcd') # optional - maple
741
"gcd - greatest common divisor of polynomials...
742
"""
743
return os.popen('echo "?%s" | maple -q'%str).read()
744
745
def help(self, str):
746
"""
747
Display Maple help about str. This is the same as typing "?str" in
748
the Maple console.
749
750
INPUT:
751
752
753
- ``str`` - a string to search for in the maple help
754
system
755
756
757
EXAMPLES::
758
759
sage: maple.help('digamma') #not tested
760
Psi - the Digamma and Polygamma functions
761
...
762
"""
763
pager()(self._help(str))
764
765
def with_package(self, package):
766
"""
767
Make a package of Maple procedures available in the interpreter.
768
769
INPUT:
770
771
772
- ``package`` - string
773
774
775
EXAMPLES: Some functions are unknown to Maple until you use with to
776
include the appropriate package.
777
778
::
779
780
sage: maple.quit() # optional -- to reset maple.
781
sage: maple('partition(10)') # optional -- requires maple
782
partition(10)
783
sage: maple('bell(10)') # optional -- requires maple
784
bell(10)
785
sage: maple.with_package('combinat') # optional -- requires maple
786
sage: maple('partition(10)') # optional -- requires maple
787
[[1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 2], [1, 1, 1, 1, 1, 1, 2, 2], [1, 1, 1, 1, 2, 2, 2], [1, 1, 2, 2, 2, 2], [2, 2, 2, 2, 2], [1, 1, 1, 1, 1, 1, 1, 3], [1, 1, 1, 1, 1, 2, 3], [1, 1, 1, 2, 2, 3], [1, 2, 2, 2, 3], [1, 1, 1, 1, 3, 3], [1, 1, 2, 3, 3], [2, 2, 3, 3], [1, 3, 3, 3], [1, 1, 1, 1, 1, 1, 4], [1, 1, 1, 1, 2, 4], [1, 1, 2, 2, 4], [2, 2, 2, 4], [1, 1, 1, 3, 4], [1, 2, 3, 4], [3, 3, 4], [1, 1, 4, 4], [2, 4, 4], [1, 1, 1, 1, 1, 5], [1, 1, 1, 2, 5], [1, 2, 2, 5], [1, 1, 3, 5], [2, 3, 5], [1, 4, 5], [5, 5], [1, 1, 1, 1, 6], [1, 1, 2, 6], [2, 2, 6], [1, 3, 6], [4, 6], [1, 1, 1, 7], [1, 2, 7], [3, 7], [1, 1, 8], [2, 8], [1, 9], [10]]
788
sage: maple('bell(10)') # optional -- requires maple
789
115975
790
sage: maple('fibonacci(10)') # optional -- requires maple
791
55
792
"""
793
self.eval('with(%s)'%package)
794
795
load = with_package
796
797
def clear(self, var):
798
"""
799
Clear the variable named var.
800
801
Unfortunately, Maple does not have a clear command. The next best
802
thing is to set equal to the constant 0, so that memory will be
803
freed.
804
805
EXAMPLES::
806
807
sage: maple.set('xx', '2') # optional - maple
808
sage: maple.get('xx') # optional - maple
809
'2'
810
sage: maple.clear('xx') # optional - maple
811
sage: maple.get('xx') # optional - maple
812
'0'
813
"""
814
self.set(var, '0')
815
816
class MapleFunction(ExpectFunction):
817
def _sage_doc_(self):
818
"""
819
Returns the Maple help for this function. This gets called when
820
doing "?" on self.
821
822
EXAMPLES::
823
824
sage: maple.gcd._sage_doc_() # optional - maple
825
"gcd - greatest common divisor of polynomials...
826
"""
827
M = self._parent
828
return M._help(self._name)
829
830
def _sage_src_(self):
831
"""
832
Returns the source code of self. This is the function that
833
eventually gets called when doing maple.gcd?? for example.
834
835
EXAMPLES::
836
837
sage: print maple.curry._sage_src_().strip() # optional - maple
838
p -> subs('_X' = args[2 .. nargs], () -> p(_X, args))
839
sage: maple.ZZZ._sage_src_() # optional - maple
840
Traceback (most recent call last):
841
...
842
Exception: no source code could be found
843
"""
844
M = self._parent
845
return M._source(self._name)
846
847
class MapleFunctionElement(FunctionElement):
848
def _sage_doc_(self):
849
"""
850
Returns the Maple help for this function. This gets called when
851
doing "?" on self.
852
853
EXAMPLES::
854
855
sage: two = maple(2) # optional - maple
856
sage: two.gcd._sage_doc_() # optional - maple
857
"gcd - greatest common divisor of polynomials...
858
"""
859
return self._obj.parent()._help(self._name)
860
861
def _sage_src_(self):
862
"""
863
Returns the source code of self.
864
865
EXAMPLES::
866
867
sage: g = maple('gcd') # optional - maple
868
sage: print g.curry._sage_src_().strip() # optional - maple
869
p -> subs('_X' = args[2 .. nargs], () -> p(_X, args))
870
sage: m = maple('2') # optional - maple
871
sage: m.ZZZ._sage_src_() # optional - maple
872
Traceback (most recent call last):
873
...
874
Exception: no source code could be found
875
"""
876
return self._obj.parent()._source(self._name)
877
878
class MapleElement(ExpectElement):
879
def __float__(self):
880
"""
881
Returns a floating point version of self.
882
883
EXAMPLES::
884
885
sage: float(maple(1/2)) # optional - maple
886
0.5
887
sage: type(_) # optional - maple
888
<type 'float'>
889
"""
890
M = self.parent()
891
return float(maple.eval('evalf(%s)'%self.name()))
892
893
def __hash__(self):
894
"""
895
Returns a 64-bit integer representing the hash of self. Since
896
Python uses 32-bit hashes, it will automatically convert the result
897
of this to a 32-bit hash.
898
899
These examples are optional, and require Maple to be installed. You
900
don't need to install any Sage packages for this.
901
902
EXAMPLES::
903
904
sage: m = maple('x^2+y^2') # optional - maple
905
sage: m.__hash__() # optional - maple
906
188724254834261060184983038723355865733L
907
sage: hash(m) # optional - maple
908
5035731711831192733
909
sage: m = maple('x^2+y^3') # optional - maple
910
sage: m.__hash__() # optional - maple
911
264835029579301191531663246434344770556L
912
sage: hash(m) # optional - maple
913
-2187277978252104690
914
"""
915
return int(maple.eval('StringTools:-Hash(convert(%s, string));'%self.name())[1:-1],16)
916
917
def __cmp__(self, other):
918
"""
919
Compare equality between self and other, using maple.
920
921
These examples are optional, and require Maple to be installed. You
922
don't need to install any Sage packages for this.
923
924
EXAMPLES::
925
926
sage: a = maple(5) # optional - maple
927
sage: b = maple(5) # optional - maple
928
sage: a == b # optional - maple
929
True
930
sage: a == 5 # optional - maple
931
True
932
933
::
934
935
sage: c = maple(3) # optional - maple
936
sage: a == c # optional - maple
937
False
938
sage: a < c # optional - maple
939
False
940
sage: a < 6 # optional - maple
941
True
942
sage: c <= a # optional - maple
943
True
944
945
::
946
947
sage: M = matrix(ZZ, 2, range(1,5)) # optional - maple
948
sage: Mm = maple(M) # optional - maple
949
sage: Mm == Mm # optional - maple
950
True
951
sage: Mm < 5 # optional - maple
952
True
953
sage: (Mm < 5) == (M < 5) # optional - maple
954
True
955
sage: 5 < Mm # optional - maple
956
False
957
958
TESTS::
959
960
sage: x = var('x')
961
sage: t = maple((x+1)^2) # optional -- requires maple
962
sage: u = maple(x^2+2*x+1) # optional -- requires maple
963
sage: u == t # todo: not implemented
964
True # returns False, should use 'testeq' in maple
965
sage: maple.eval('testeq(%s = %s)'%(t.name(),u.name())) # optional - maple
966
'true'
967
"""
968
P = self.parent()
969
if P.eval("evalb(%s %s %s)"%(self.name(), P._equality_symbol(),
970
other.name())) == P._true_symbol():
971
return 0
972
# Maple does not allow comparing objects of different types and
973
# it raises an error in this case.
974
# We catch the error, and return True for <
975
try:
976
if P.eval("evalb(%s %s %s)"%(self.name(), P._lessthan_symbol(), other.name())) == P._true_symbol():
977
return -1
978
except RuntimeError, e:
979
msg = str(e)
980
if 'is not valid' in msg and 'to < or <=' in msg:
981
if (hash(str(self)) < hash(str(other))):
982
return -1
983
else:
984
return 1
985
else:
986
raise RuntimeError, e
987
if P.eval("evalb(%s %s %s)"%(self.name(), P._greaterthan_symbol(), other.name())) == P._true_symbol():
988
return 1
989
# everything is supposed to be comparable in Python, so we define
990
# the comparison thus when no comparable in interfaced system.
991
if (hash(self) < hash(other)):
992
return -1
993
else:
994
return 1
995
996
def _mul_(self, right):
997
"""
998
These examples are optional, and require Maple to be installed. You
999
don't need to install any Sage packages for this.
1000
1001
EXAMPLES::
1002
1003
sage: t = maple(5); u = maple(3) # optional - maple
1004
sage: t*u # optional - maple
1005
15
1006
sage: M = matrix(ZZ,2,range(4)) # optional - maple
1007
sage: Mm = maple(M) # optional - maple
1008
sage: Mm*Mm # optional - maple
1009
Matrix(2, 2, [[2,3],[6,11]])
1010
1011
::
1012
1013
sage: v = vector(ZZ,2,[2,3])
1014
sage: vm = maple(v) # optional - maple
1015
sage: vm*Mm # optional - maple
1016
Vector[row](2, [6,11])
1017
1018
::
1019
1020
sage: t*Mm # optional - maple
1021
Matrix(2, 2, [[0,5],[10,15]])
1022
"""
1023
P = self._check_valid()
1024
try:
1025
return P.new('%s . %s'%(self._name, right._name))
1026
except Exception, msg:
1027
raise TypeError,msg
1028
1029
def trait_names(self):
1030
"""
1031
EXAMPLES::
1032
1033
sage: a = maple(2) # optional - maple
1034
sage: 'sin' in a.trait_names() # optional - maple
1035
True
1036
"""
1037
return self.parent().trait_names()
1038
1039
def __repr__(self):
1040
"""
1041
Return a string representation of self.
1042
1043
These examples are optional, and require Maple to be installed. You
1044
don't need to install any Sage packages for this.
1045
1046
EXAMPLES::
1047
1048
sage: x = var('x')
1049
sage: maple(x) # optional - maple
1050
x
1051
sage: maple(5) # optional - maple
1052
5
1053
sage: M = matrix(QQ,2,range(4))
1054
sage: maple(M) # optional - maple
1055
Matrix(2, 2, [[0,1],[2,3]])
1056
"""
1057
self._check_valid()
1058
return self.parent().get(self._name)
1059
1060
def _latex_(self):
1061
r"""
1062
You can output Maple expressions in latex.
1063
1064
EXAMPLES::
1065
1066
sage: print latex(maple('(x^4 - y)/(y^2-3*x)')) # optional -- requires maple
1067
{\frac {{x}^{4}-y}{{y}^{2}-3\,x}}
1068
sage: print latex(maple(pi - e^3)) # optional -- requires maple
1069
\pi - \left( {e^{1}} \right) ^{3}
1070
1071
.. note::
1072
1073
Some expressions might require the Maple style file
1074
``maple2e.sty`` in order to latex correctly.
1075
"""
1076
return self.parent().eval('latex(%s)'%self.name())
1077
1078
def _sage_(self):
1079
r"""
1080
Convert a maple expression back to a Sage expression.
1081
1082
This currently does not implement a parser for the Maple output language,
1083
therefore only very simple expressions will convert successfully.
1084
1085
EXAMPLE::
1086
1087
sage: m = maple('x^2 + 5*y') # optional - requires maple
1088
sage: m.sage() # optional - requires maple
1089
x^2 + 5*y
1090
1091
::
1092
1093
sage: m = maple('sin(sqrt(1-x^2)) * (1 - cos(1/x))^2') # optional - requires maple
1094
sage: m.sage() # optional - requires maple
1095
(cos(1/x) - 1)^2*sin(sqrt(-x^2 + 1))
1096
1097
"""
1098
result = repr(self)
1099
# The next few lines are a very crude excuse for a maple "parser".
1100
result = result.replace("Pi", "pi")
1101
1102
try:
1103
from sage.symbolic.all import SR
1104
return SR(result)
1105
except:
1106
raise NotImplementedError, "Unable to parse Maple output: %s" % result
1107
1108
# An instance
1109
maple = Maple(script_subdirectory='user')
1110
1111
def reduce_load_Maple():
1112
"""
1113
Returns the maple object created in sage.interfaces.maple.
1114
1115
EXAMPLES::
1116
1117
sage: from sage.interfaces.maple import reduce_load_Maple
1118
sage: reduce_load_Maple()
1119
Maple
1120
"""
1121
return maple
1122
1123
1124
import os
1125
def maple_console():
1126
"""
1127
Spawn a new Maple command-line session.
1128
1129
EXAMPLES::
1130
1131
sage: maple_console() #not tested
1132
|^/| Maple 11 (IBM INTEL LINUX)
1133
._|\| |/|_. Copyright (c) Maplesoft, a division of Waterloo Maple Inc. 2007
1134
\ MAPLE / All rights reserved. Maple is a trademark of
1135
<____ ____> Waterloo Maple Inc.
1136
| Type ? for help.
1137
>
1138
"""
1139
os.system('maple')
1140
1141
1142
def __doctest_cleanup():
1143
"""
1144
EXAMPLES::
1145
1146
sage: from sage.interfaces.maple import __doctest_cleanup
1147
sage: m = maple(2) # optional - maple
1148
sage: maple.is_running() # optional - maple
1149
True
1150
sage: __doctest_cleanup()
1151
sage: maple.is_running()
1152
False
1153
"""
1154
import sage.interfaces.quit
1155
sage.interfaces.quit.expect_quitall()
1156
1157
1158
1159
"""
1160
The following only works in Maple >= 9, I guess, but could
1161
be useful.
1162
1163
From Jaap Spies: In addition Maple has a nice feature the function
1164
1165
> FunctionAdvisor();
1166
1167
> FunctionAdvisor(topics, quiet);
1168
[DE, analytic_extension, asymptotic_expansion, branch_cuts,
1169
branch_points, calling_sequence, class_members,
1170
classify_function, definition, describe, differentiation_rule,
1171
function_classes, identities, integral_form,
1172
known_functions, relate, series, singularities, special_values,
1173
specialize, sum_form, synonyms]
1174
1175
> FunctionAdvisor(syntax, hypergeom);
1176
hypergeom([a, b], [c], z)
1177
1178
Eventually this could be used to do an intelligent command
1179
completion.
1180
"""
1181
1182