Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/interfaces/mupad.py
4057 views
1
r"""
2
Interface to MuPAD
3
4
AUTHOR:
5
-- Mike Hansen
6
-- William Stein
7
8
You must have the optional commercial MuPAD interpreter installed and
9
available as the command \code{mupkern} in your PATH in order to use
10
this interface. You do not have to install any optional \sage
11
packages.
12
13
TESTS:
14
sage: mupad.package('"MuPAD-Combinat"') # optional - mupad
15
sage: combinat = mupad.combinat # optional - mupad
16
sage: examples = mupad.examples # optional - mupad
17
sage: S = examples.SymmetricFunctions() # optional - mupad
18
sage: S.s[2,1]^2 # optional - mupad
19
s[3, 3] + s[4, 2] + s[2, 2, 1, 1] + s[2, 2, 2] + 2 s[3, 2, 1] + s[4, 1, 1] +
20
s[3, 1, 1, 1]
21
sage: S.omega( S.s[3] ) # optional - mupad
22
s[1, 1, 1]
23
sage: s = S.s # optional - mupad
24
sage: p = S.p # optional - mupad
25
sage: s(s[2,1] + p[2,1]) # optional - mupad
26
s[2, 1] + s[3] - s[1, 1, 1]
27
sage: s(_) # optional - mupad
28
s[2, 1] + s[3] - s[1, 1, 1]
29
30
sage: combinat.tableaux.list(3) # optional - mupad # note: the order of the result seems to depend on the version of MuPAD / MuPAD-Combinat
31
-- +---+ --
32
| | 3 | |
33
| +---+ +---+ +---+ |
34
| | 3 | | 2 | | 2 | |
35
| +---+---+---+ +---+---+ +---+---+ +---+ |
36
| | 1 | 2 | 3 |, | 1 | 2 |, | 1 | 3 |, | 1 | |
37
-- +---+---+---+ +---+---+ +---+---+ +---+ --
38
sage: three = mupad(3) # optional - mupad
39
sage: three.combinat.tableaux.list() # optional - mupad
40
-- +---+ --
41
| | 3 | |
42
| +---+ +---+ +---+ |
43
| | 3 | | 2 | | 2 | |
44
| +---+---+---+ +---+---+ +---+---+ +---+ |
45
| | 1 | 2 | 3 |, | 1 | 2 |, | 1 | 3 |, | 1 | |
46
-- +---+---+---+ +---+---+ +---+---+ +---+ --
47
sage: t = _[1] # optional - mupad
48
sage: t # optional - mupad
49
+---+---+---+
50
| 1 | 2 | 3 |
51
+---+---+---+
52
sage: combinat.tableaux.conjugate(t) # optional - mupad
53
+---+
54
| 3 |
55
+---+
56
| 2 |
57
+---+
58
| 1 |
59
+---+
60
61
sage: combinat.ribbonsTableaux.list([2,2],[1,1],2) # optional - mupad
62
-- +---+---+ +---+---+ --
63
| | | 2 | | 2 | |
64
| + + +, +---+---+ |
65
| | 1 | | | 1 | |
66
-- +---+---+ +---+---+ --
67
sage: combinat.tableaux.kAtom([2,1],3) # optional - mupad
68
-- +---+ --
69
| | 2 | |
70
| +---+---+ |
71
| | 1 | 1 | |
72
-- +---+---+ --
73
sage: M = S.Macdonald() # optional - mupad
74
sage: a = M.P[1]^2 # optional - mupad
75
sage: mupad.mapcoeffs(a, 'normal') # optional - mupad
76
q - t + q t - 1
77
P[2] + --------------- P[1, 1]
78
q t - 1
79
80
"""
81
82
#############################################################################
83
# Copyright (C) 2008 Mike Hansen <[email protected]>
84
# William Stein <[email protected]>
85
#
86
# Distributed under the terms of the GNU General Public License (GPL)
87
#
88
# http://www.gnu.org/licenses/
89
#############################################################################
90
91
import os
92
93
from expect import (Expect, ExpectElement, ExpectFunction,
94
FunctionElement, AsciiArtString)
95
96
97
from sage.misc.misc import verbose, DOT_SAGE
98
99
COMMANDS_CACHE = '%s/mupad_commandlist_cache.sobj'%DOT_SAGE
100
PROMPT = ">>"
101
seq = 0
102
103
class Mupad(Expect):
104
"""
105
Interface to the MuPAD interpreter.
106
"""
107
def __init__(self, maxread=1000, script_subdirectory="", server=None, server_tmpdir=None, logfile=None):
108
"""
109
Create an instance of the MuPAD interpreter.
110
111
EXAMPLES:
112
sage: mupad == loads(dumps(mupad)) # optional - mupad
113
True
114
"""
115
Expect.__init__(self,
116
name = 'MuPAD',
117
prompt = PROMPT,
118
# the -U SAGE=TRUE allows for MuPAD programs to test whether they are run from Sage
119
command = "mupkern -P e -U SAGE=TRUE",
120
maxread = maxread,
121
script_subdirectory = script_subdirectory,
122
server = server,
123
server_tmpdir = server_tmpdir,
124
restart_on_ctrlc = False,
125
verbose_start = False,
126
logfile = None)
127
128
129
130
131
def _function_class(self):
132
"""
133
EXAMPLES:
134
sage: mupad._function_class()
135
<class 'sage.interfaces.mupad.MupadFunction'>
136
137
sage: mdiff = mupad.diff; mdiff # optional - mupad
138
diff
139
sage: type(mdiff) # optional -- mupad
140
<class 'sage.interfaces.mupad.MupadFunction'>
141
"""
142
return MupadFunction
143
144
def __reduce__(self):
145
"""
146
EXAMPLES:
147
sage: mupad.__reduce__()
148
(<function reduce_load_mupad at 0x...>, ())
149
150
"""
151
return reduce_load_mupad, tuple([])
152
153
def _read_in_file_command(self, filename):
154
"""
155
EXAMPLES:
156
sage: mupad._read_in_file_command('test')
157
'read("test")'
158
159
sage: filename = tmp_filename()
160
sage: f = open(filename, 'w')
161
sage: f.write('x := 2;\n')
162
sage: f.close()
163
sage: mupad.read(filename) #optional -- requires MuPAD
164
sage: mupad.get('x').strip() # optional - mupad
165
'2'
166
167
"""
168
return 'read("%s")'%filename
169
170
def _quit_string(self):
171
"""
172
EXAMPLES:
173
sage: mupad._quit_string()
174
'quit'
175
"""
176
return 'quit'
177
178
def _install_hints(self):
179
"""
180
Hints for installing MuPAD on your computer.
181
182
EXAMPLES:
183
sage: print mupad._install_hints()
184
<BLANKLINE>
185
In order to use the MuPAD interface you need to have MuPAD installed
186
...
187
188
"""
189
return """
190
In order to use the MuPAD interface you need to have MuPAD installed
191
and have a script in your PATH called "mupkern" that runs the
192
command-line version of MuPAD.
193
194
(1) You might have to buy MuPAD.
195
196
(2) * LINUX: The mupkern script comes standard with your Mupad install.
197
198
* APPLE OS X:
199
???
200
"""
201
202
def expect(self):
203
"""
204
EXAMPLES:
205
sage: a = mupad(1) # optional - mupad
206
sage: mupad.expect() # optional - mupad
207
<pexpect.spawn instance at 0x...>
208
"""
209
return self._expect
210
211
def console(self):
212
"""
213
Spawn a new MuPAD command-line session.
214
215
EXAMPLES:
216
sage: mupad.console() #not tested
217
218
*----* MuPAD Pro 4.0.2 -- The Open Computer Algebra System
219
/| /|
220
*----* | Copyright (c) 1997 - 2007 by SciFace Software
221
| *--|-* All rights reserved.
222
|/ |/
223
*----* Licensed to: ...
224
225
"""
226
mupad_console()
227
228
def eval(self, code, strip=True, **kwds):
229
"""
230
EXAMPLES:
231
sage: mupad.eval('2+2') # optional - mupad
232
4
233
234
"""
235
s = Expect.eval(self, code, **kwds)
236
return AsciiArtString(s)
237
238
def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True,
239
need_output=True, restart_if_needed=False):
240
"""
241
EXAMPLES:
242
sage: mupad._eval_line('2+2') # optional - mupad
243
' 4'
244
sage: mupad._eval_line('x::asdf') # optional - mupad
245
Traceback (most recent call last):
246
...
247
RuntimeError: Unknown slot "x::asdf" [slot]
248
249
"""
250
if self._expect is None:
251
self._start()
252
if not need_output:
253
E = self._expect
254
E.sendline(line)
255
return
256
257
global seq
258
seq += 1
259
START = '__start__(%s+1)'%seq
260
END = '__end__(%s+1)'%seq
261
line = '%s; %s; %s;'%(START, line, END)
262
START = '__start__(%s)'%(seq+1)
263
END = '__end__(%s)'%(seq+1)
264
265
E = self._expect
266
E.sendline(line)
267
E.expect(PROMPT)
268
z = E.before
269
i = z.find(START)
270
if i == -1:
271
raise RuntimeError, "%s\nError evaluating code in MuPAD"%z
272
z = z[i+len(START)+2:]
273
z = z.rstrip().rstrip(END).rstrip('"').rstrip().strip('\n').strip('\r').strip('\n').replace('\\\r\n','')
274
i = z.find('Error: ')
275
if i != -1:
276
raise RuntimeError, z[i + 7:]
277
return z
278
279
def cputime(self, t=None):
280
"""
281
EXAMPLES:
282
sage: t = mupad.cputime() #random, optional -- requires MuPAD
283
0.11600000000000001
284
"""
285
if t is None:
286
return float(str(self('time()')))/1000
287
else:
288
return float(str(self('time() - %s'%float(t))))/1000
289
290
def set(self, var, value):
291
"""
292
Set the variable var to the given value.
293
294
EXAMPLES:
295
sage: mupad.set('a', 4) # optional - mupad
296
sage: mupad.get('a').strip() # optional - mupad
297
'4'
298
"""
299
cmd = '%s:=%s:'%(var,value)
300
out = self.eval(cmd)
301
i = out.find('Error: ')
302
if i != -1:
303
raise RuntimeError, out[i + 7:]
304
305
def get(self, var):
306
"""
307
Get the value of the variable var.
308
309
EXAMPLES:
310
sage: mupad.set('a', 4) # optional - mupad
311
sage: mupad.get('a').strip() # optional - mupad
312
'4'
313
314
"""
315
s = self.eval('%s'%var)
316
i = s.find('=')
317
return s[i+1:]
318
319
def _object_class(self):
320
"""
321
EXAMPLES:
322
sage: mupad._object_class()
323
<class 'sage.interfaces.mupad.MupadElement'>
324
"""
325
return MupadElement
326
327
def _equality_symbol(self):
328
"""
329
EXAMPLES:
330
sage: mupad._equality_symbol()
331
'='
332
"""
333
return '='
334
335
def _assign_symbol(self):
336
"""
337
EXAMPLES:
338
sage: mupad._assign_symbol()
339
':='
340
"""
341
return ":="
342
343
def _continuation_prompt(self):
344
"""
345
EXAMPLES:
346
sage: mupad._continuation_prompt()
347
'&>'
348
"""
349
return "&>"
350
351
def _commands(self):
352
"""
353
Return list of all commands defined in MuPAD.
354
355
EXAMPLES:
356
sage: cmds = mupad._commands() # optional - mupad
357
sage: len(cmds) > 100 # optional - mupad
358
True
359
sage: 'diff' in cmds # optional - mupad
360
True
361
"""
362
try:
363
v = sum([self.completions(chr(65+n)) for n in range(26)], []) + \
364
sum([self.completions(chr(97+n)) for n in range(26)], [])
365
except RuntimeError:
366
print "\n"*3
367
print "*"*70
368
print "WARNING: You do not have a working version of MuPAD installed!"
369
print "*"*70
370
v = []
371
v.sort()
372
return v
373
374
def trait_names(self, verbose=True, use_disk_cache=True):
375
"""
376
EXAMPLES:
377
sage: names = mupad.trait_names() # optional - mupad
378
sage: len(names) > 100 # optional - mupad
379
True
380
sage: 'combinat' in names # optional - mupad
381
True
382
"""
383
try:
384
return self.__trait_names
385
except AttributeError:
386
import sage.misc.persist
387
if use_disk_cache:
388
try:
389
self.__trait_names = sage.misc.persist.load(COMMANDS_CACHE)
390
return self.__trait_names
391
except IOError:
392
pass
393
if verbose:
394
print "\nBuilding MuPAD command completion list (this takes"
395
print "a few seconds only the first time you do it)."
396
print "To force rebuild later, delete %s."%COMMANDS_CACHE
397
v = self._commands()
398
self.__trait_names = v
399
if len(v) > 200:
400
# MuPAD is actually installed.
401
sage.misc.persist.save(v, COMMANDS_CACHE)
402
return v
403
404
def completions(self, string, strip=False):
405
"""
406
EXAMPLES:
407
sage: mupad.completions('linal') # optional - mupad
408
['linalg']
409
"""
410
res = self.eval('_pref(Complete)("%s")'%string).strip()
411
res = res.replace('\n', '').split(',')
412
res = [s.strip().strip('"') for s in res]
413
res = [s for s in res if not s.endswith('::')]
414
if strip:
415
n = len(string)
416
res = [s[n:] for s in res]
417
418
return res if res != [''] else []
419
420
421
422
class MupadFunction(ExpectFunction):
423
def _sage_doc_(self):
424
"""
425
EXAMPLES:
426
sage: mupad.diff._sage_doc_()
427
No help on diff available
428
"""
429
M = self._parent
430
return M.help(self._name)
431
432
def __getattr__(self, attrname):
433
"""
434
EXAMPLES:
435
sage: mupad.linalg.addRow
436
linalg::addRow
437
"""
438
if attrname[:1] == "_":
439
raise AttributeError
440
return MupadFunction(self._parent, self._name+"::"+attrname)
441
442
def trait_names(self):
443
"""
444
EXAMPLES:
445
sage: mupad.linalg.trait_names() # optional - mupad
446
['addCol',
447
'addRow',
448
...
449
'wiedemann']
450
451
"""
452
res = self._parent.completions(self._name+"::", strip=True)
453
return res if res != [] else self._parent.trait_names()
454
455
class MupadFunctionElement(FunctionElement):
456
def _sage_doc_(self):
457
"""
458
EXAMPLES:
459
sage: x = mupad('x') # optional - mupad
460
sage: x.diff._sage_doc_() # optional - mupad
461
No help on diff available
462
463
"""
464
return self._obj.parent().help(self._name)
465
466
def __getattr__(self, attrname):
467
"""
468
EXAMPLES:
469
sage: mupad.package('"MuPAD-Combinat"') # optional - mupad-Combinat
470
sage: combinat = mupad.combinat # optional - mupad-Combinat
471
sage: three = mupad(3) # optional - mupad-Combinat
472
sage: type(three.combinat) # optional - mupad-Combinat
473
<class 'sage.interfaces.mupad.MupadFunctionElement'>
474
sage: tableaux = three.combinat.tableaux # optional - mupad-Combinat
475
sage: type(tableaux) # optional - mupad-Combinat
476
<class 'sage.interfaces.mupad.MupadFunctionElement'>
477
"""
478
P = self._obj.parent()
479
if attrname[:1] == "_":
480
if attrname not in self.__dict__:
481
raise AttributeError
482
else:
483
return self.__dict__[attrname]
484
name = self._name+"::"+attrname
485
if P.eval('type(%s)'%name) == "DOM_DOMAIN":
486
return MupadElement(P, name)
487
else:
488
return MupadFunctionElement(self._obj, name)
489
490
def trait_names(self):
491
"""
492
EXAMPLES:
493
sage: three = mupad(3) # optional - mupad
494
sage: 'list' in three.combinat.tableaux.trait_names() #optional
495
True
496
"""
497
P = self._obj.parent()
498
res = P.completions(self._name+"::", strip=True)
499
return res if res != [] else P.trait_names()
500
501
502
def __call__(self, *args):
503
"""
504
EXAMPLES:
505
sage: mupad.package('"MuPAD-Combinat"') # optional - mupad-Combinat
506
sage: combinat = mupad.combinat # optional - mupad-Combinat
507
sage: examples = mupad.examples # optional - mupad-Combinat
508
sage: S = examples.SymmetricFunctions() # optional - mupad-Combinat
509
sage: type(S.omega) # optional - mupad-Combinat
510
<class 'sage.interfaces.mupad.MupadFunctionElement'>
511
sage: S.omega(S.s[3]) # optional - mupad-Combinat
512
s[1, 1, 1]
513
"""
514
P = self._obj.parent()
515
if P.eval('type(%s)'%(self._obj.name())).strip() == "DOM_DOMAIN":
516
return P.function_call(self._name, list(args))
517
else:
518
return P.function_call(self._name, [self._obj] + list(args))
519
520
class MupadElement(ExpectElement):
521
def __getattr__(self, attrname):
522
"""
523
EXAMPLES:
524
sage: mupad.package('"MuPAD-Combinat"') # optional - mupad-Combinat
525
sage: S = mupad.examples.SymmetricFunctions() #optional
526
sage: type(S) # optional - mupad-Combinat
527
<class 'sage.interfaces.mupad.MupadElement'>
528
sage: S.s # optional - mupad-Combinat
529
(examples::SymmetricFunctions(Dom::ExpressionField()))::s
530
531
sage: x = mupad('x') # optional - mupad-Combinat
532
sage: x.diff(x) # optional - mupad-Combinat
533
1
534
535
"""
536
if attrname[:1] == "_":
537
if attrname not in self.__dict__:
538
raise AttributeError
539
else:
540
return self.__dict__[attrname]
541
P = self.parent()
542
543
name = self._name + "::" + attrname
544
try:
545
if P.eval('type(%s::%s)'%(self.name(),attrname)).strip() == "DOM_DOMAIN":
546
return P.new("%s::%s"%(self.name(),attrname))
547
else:
548
return MupadFunctionElement(self, name)
549
except RuntimeError, err:
550
if 'Unknown slot' in str(err):
551
return MupadFunctionElement(self, attrname)
552
else:
553
raise err
554
555
556
def trait_names(self):
557
"""
558
EXAMPLES:
559
sage: mupad.package('"MuPAD-Combinat"') # optional - mupad-Combinat
560
sage: S = mupad.examples.SymmetricFunctions() # optional - mupad-Combinat
561
sage: 'HallLittlewood' in S.trait_names() # optional - mupad-Combinat
562
True
563
"""
564
res = self.parent().completions(self.name()+"::", strip=True)
565
return res if res != [] else self.parent().trait_names()
566
567
def __repr__(self):
568
"""
569
EXAMPLES:
570
sage: mupad.package('"MuPAD-Combinat"') # optional - mupad-Combinat
571
sage: S = mupad.examples.SymmetricFunctions(); S # optional - mupad-Combinat
572
examples::SymmetricFunctions(Dom::ExpressionField())
573
"""
574
self._check_valid()
575
return self.parent().get(self._name)
576
577
def _latex_(self):
578
r"""
579
EXAMPLES:
580
sage: mupad.package('"MuPAD-Combinat"') # optional - mupad-Combinat
581
sage: S = mupad.examples.SymmetricFunctions() # optional - mupad-Combinat
582
sage: latex(S) # optional - mupad-Combinat
583
\mathrm{examples}{::}\mathrm{SymmetricFunctions}\left(\mathbb{E}\right)
584
"""
585
self._check_valid()
586
P = self.parent()
587
s = P._eval_line('generate::TeX(%s)'%self.name())
588
s = s.replace('\\\\','\\').strip().strip('"')
589
return s
590
591
def __len__(self):
592
r"""
593
The analogue in MuPAD of Python's len is the method nops
594
595
EXAMPLES::
596
597
sage: len(mupad([1,2,3])) # indirect doctest # optional - mupad
598
3
599
sage: type(len(mupad([1,2,3]))) # optional - mupad
600
<type 'int'>
601
602
sage: len(mupad(4)) # optional - mupad
603
1
604
605
Implementing this is necessary for using MuPAD's lists as
606
standard containers::
607
608
sage: map(ZZ, list(mupad([1,2,3]))) # optional - mupad
609
[1, 2, 3]
610
611
sage: [int(x) for x in mupad([1,2,3]) ] # optional - mupad
612
[1, 2, 3]
613
614
sage: [int(x) for x in mupad("{1,2,3,5}") ] # optional - mupad
615
[1, 2, 3, 5]
616
617
"""
618
return mupad.nops(self)
619
620
# An instance
621
mupad = Mupad(script_subdirectory='user')
622
623
def reduce_load_mupad():
624
"""
625
EXAMPLES:
626
sage: from sage.interfaces.mupad import reduce_load_mupad
627
sage: reduce_load_mupad()
628
Mupad
629
"""
630
return mupad
631
632
import os
633
def mupad_console():
634
"""
635
Spawn a new MuPAD command-line session.
636
637
EXAMPLES:
638
sage: from sage.interfaces.mupad import mupad_console
639
sage: mupad_console() #not tested
640
641
*----* MuPAD Pro 4.0.2 -- The Open Computer Algebra System
642
/| /|
643
*----* | Copyright (c) 1997 - 2007 by SciFace Software
644
| *--|-* All rights reserved.
645
|/ |/
646
*----* Licensed to: ...
647
648
"""
649
os.system('mupkern')
650
651
652
def __doctest_cleanup():
653
"""
654
EXAMPLES:
655
sage: from sage.interfaces.mupad import __doctest_cleanup
656
sage: m = mupad(2) # optional - mupad
657
sage: mupad.is_running() # optional - mupad
658
True
659
sage: __doctest_cleanup()
660
sage: mupad.is_running() # optional - mupad
661
False
662
"""
663
import sage.interfaces.quit
664
sage.interfaces.quit.expect_quitall()
665
666
667