Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/interfaces/octave.py
4069 views
1
r"""
2
Interface to Octave
3
4
Octave is an open source MATLAB-like program with numerical
5
routines for integrating, solving systems of equations, special
6
functions, and solving (numerically) differential equations. Please
7
see http://octave.sourceforge.net for more details.
8
9
The commands in this section only work if you have the optional
10
"octave" interpreter installed and available in your PATH. It's not
11
necessary to install any special Sage packages.
12
13
EXAMPLES::
14
15
sage: octave.eval('2+2') # optional -- requires Octave
16
'ans = 4'
17
18
sage: a = octave(10) # optional -- requires Octave
19
sage: a**10 # optional -- requires Octave
20
1e+10
21
22
LOG: - creation (William Stein) - ? (David Joyner, 2005-12-18) -
23
Examples (David Joyner, 2005-01-03)
24
25
Computation of Special Functions
26
--------------------------------
27
28
Octave implements computation of the following special functions
29
(see the maxima and gp interfaces for even more special
30
functions)::
31
32
airy
33
Airy functions of the first and second kind, and their derivatives.
34
airy(0,x) = Ai(x), airy(1,x) = Ai'(x), airy(2,x) = Bi(x), airy(3,x) = Bi'(x)
35
besselj
36
Bessel functions of the first kind.
37
bessely
38
Bessel functions of the second kind.
39
besseli
40
Modified Bessel functions of the first kind.
41
besselk
42
Modified Bessel functions of the second kind.
43
besselh
44
Compute Hankel functions of the first (k = 1) or second (k = 2) kind.
45
beta
46
The Beta function,
47
beta (a, b) = gamma (a) * gamma (b) / gamma (a + b).
48
betainc
49
The incomplete Beta function,
50
erf
51
The error function,
52
erfinv
53
The inverse of the error function.
54
gamma
55
The Gamma function,
56
gammainc
57
The incomplete gamma function,
58
59
For example,
60
61
::
62
63
sage: octave("airy(3,2)") # optional -- requires Octave
64
4.10068
65
sage: octave("beta(2,2)") # optional -- requires Octave
66
0.166667
67
sage: octave("betainc(0.2,2,2)") # optional -- requires Octave
68
0.104
69
sage: octave("besselh(0,2)") # optional -- requires Octave
70
(0.223891,0.510376)
71
sage: octave("besselh(0,1)") # optional -- requires Octave
72
(0.765198,0.088257)
73
sage: octave("besseli(1,2)") # optional -- requires Octave
74
1.59064
75
sage: octave("besselj(1,2)") # optional -- requires Octave
76
0.576725
77
sage: octave("besselk(1,2)") # optional -- requires Octave
78
0.139866
79
sage: octave("erf(0)") # optional -- requires Octave
80
0
81
sage: octave("erf(1)") # optional -- requires Octave
82
0.842701
83
sage: octave("erfinv(0.842)") # optional -- requires Octave
84
0.998315
85
sage: octave("gamma(1.5)") # optional -- requires Octave
86
0.886227
87
sage: octave("gammainc(1.5,1)") # optional -- requires Octave
88
0.77687
89
90
The Octave interface reads in even very long input (using files) in
91
a robust manner::
92
93
sage: t = '"%s"'%10^10000 # ten thousand character string.
94
sage: a = octave.eval(t + ';') # optional -- requires Octave, < 1/100th of a second
95
sage: a = octave(t) # optional -- requires Octave
96
97
Note that actually reading a back out takes forever. This *must*
98
be fixed ASAP - see
99
http://trac.sagemath.org/sage_trac/ticket/940/.
100
101
Tutorial
102
--------
103
104
EXAMPLES::
105
106
sage: octave('4+10') # optional -- requires Octave
107
14
108
sage: octave('date') # optional -- requires Octave; random output
109
18-Oct-2007
110
sage: octave('5*10 + 6') # optional -- requires Octave
111
56
112
sage: octave('(6+6)/3') # optional -- requires Octave
113
4
114
sage: octave('9')^2 # optional -- requires Octave
115
81
116
sage: a = octave(10); b = octave(20); c = octave(30) # optional -- requires Octave
117
sage: avg = (a+b+c)/3 # optional -- requires Octave
118
sage: avg # optional -- requires Octave
119
20
120
sage: parent(avg) # optional -- requires Octave
121
Octave
122
123
::
124
125
sage: my_scalar = octave('3.1415') # optional -- requires Octave
126
sage: my_scalar # optional -- requires Octave
127
3.1415
128
sage: my_vector1 = octave('[1,5,7]') # optional -- requires Octave
129
sage: my_vector1 # optional -- requires Octave
130
1 5 7
131
sage: my_vector2 = octave('[1;5;7]') # optional -- requires Octave
132
sage: my_vector2 # optional -- requires Octave
133
1
134
5
135
7
136
sage: my_vector1 * my_vector2 # optional -- requires Octave
137
75
138
"""
139
140
#*****************************************************************************
141
# Copyright (C) 2005 William Stein <[email protected]>
142
#
143
# Distributed under the terms of the GNU General Public License (GPL)
144
#
145
# This code is distributed in the hope that it will be useful,
146
# but WITHOUT ANY WARRANTY; without even the implied warranty of
147
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
148
# General Public License for more details.
149
#
150
# The full text of the GPL is available at:
151
#
152
# http://www.gnu.org/licenses/
153
#*****************************************************************************
154
155
import os
156
from expect import Expect, ExpectElement
157
from sage.misc.misc import verbose
158
159
160
class Octave(Expect):
161
r"""
162
Interface to the Octave interpreter.
163
164
EXAMPLES::
165
166
sage: octave.eval("a = [ 1, 1, 2; 3, 5, 8; 13, 21, 33 ]") # optional -- requires Octave
167
'a =\n\n 1 1 2\n 3 5 8\n 13 21 33\n\n'
168
sage: octave.eval("b = [ 1; 3; 13]") # optional -- requires Octave
169
'b =\n\n 1\n 3\n 13\n\n'
170
sage: octave.eval("c=a \\ b") # solves linear equation: a*c = b # optional -- requires Octave; random output
171
'c =\n\n 1\n 7.21645e-16\n -7.21645e-16\n\n'
172
sage: octave.eval("c") # optional -- requires Octave; random output
173
'c =\n\n 1\n 7.21645e-16\n -7.21645e-16\n\n'
174
"""
175
def __init__(self, maxread=100, script_subdirectory="", logfile=None, server=None, server_tmpdir=None):
176
"""
177
EXAMPLES::
178
179
sage: octave == loads(dumps(octave))
180
True
181
"""
182
Expect.__init__(self,
183
name = 'octave',
184
prompt = '>',
185
command = "sage-native-execute octave --no-line-editing --silent",
186
maxread = maxread,
187
server = server,
188
server_tmpdir = server_tmpdir,
189
script_subdirectory = script_subdirectory,
190
restart_on_ctrlc = False,
191
verbose_start = False,
192
logfile = logfile,
193
eval_using_file_cutoff=100)
194
195
def __reduce__(self):
196
"""
197
EXAMPLES::
198
199
sage: octave.__reduce__()
200
(<function reduce_load_Octave at 0x...>, ())
201
"""
202
return reduce_load_Octave, tuple([])
203
204
def _read_in_file_command(self, filename):
205
"""
206
EXAMPLES::
207
208
sage: filename = tmp_filename()
209
sage: octave._read_in_file_command(filename)
210
'source("...");'
211
"""
212
return 'source("%s");'%filename
213
214
def _quit_string(self):
215
"""
216
EXAMPLES::
217
218
sage: octave._quit_string()
219
'quit;'
220
"""
221
return 'quit;'
222
223
def _install_hints(self):
224
"""
225
Returns hints on how to install Octave.
226
227
EXAMPLES::
228
229
sage: print octave._install_hints()
230
You must get ...
231
"""
232
return """
233
You must get the program "octave" in order to use Octave
234
from Sage. You can read all about Octave at
235
http://www.gnu.org/software/octave/
236
237
LINUX / WINDOWS (colinux):
238
Do apt-get install octave as root on your machine
239
(or, in Windows, in the colinux console).
240
241
OS X:
242
* This website has links to binaries for OS X PowerPC
243
and OS X Intel builds of the latest version of Octave:
244
http://hpc.sourceforge.net/
245
Once you get the tarball from there, go to the / directory
246
and type
247
tar zxvf octave-intel-bin.tar.gz
248
to extract it to usr/local/... Make sure /usr/local/bin
249
is in your PATH. Then type "octave" and verify that
250
octave starts up.
251
* Darwin ports and fink have Octave as well.
252
"""
253
254
def quit(self, verbose=False):
255
"""
256
EXAMPLES::
257
258
sage: o = Octave()
259
sage: o._start() #optional -- requires Octave
260
sage: o.quit(True) #optional -- requires Octave
261
Exiting spawned Octave process.
262
"""
263
# Don't bother, since it just hangs in some cases, and it
264
# isn't necessary, since octave behaves well with respect
265
# to signals.
266
if not self._expect is None:
267
if verbose:
268
print "Exiting spawned %s process."%self
269
return
270
271
def _start(self):
272
"""
273
Starts the Octave process.
274
275
EXAMPLES::
276
277
sage: o = Octave() #optional -- requires Octave
278
sage: o.is_running() #optional -- requires Octave
279
False
280
sage: o._start() #optional -- requires Octave
281
sage: o.is_running() #optional -- requires Octave
282
True
283
"""
284
Expect._start(self)
285
self.eval("page_screen_output=0;")
286
self.eval("format none;")
287
288
def set(self, var, value):
289
"""
290
Set the variable var to the given value.
291
292
EXAMPLES::
293
294
sage: octave.set('x', '2') #optional -- requires Octave
295
sage: octave.get('x') #optional -- requires Octave
296
' 2'
297
"""
298
cmd = '%s=%s;'%(var,value)
299
out = self.eval(cmd)
300
if out.find("error") != -1:
301
raise TypeError, "Error executing code in Octave\nCODE:\n\t%s\nOctave ERROR:\n\t%s"%(cmd, out)
302
303
def get(self, var):
304
"""
305
Get the value of the variable var.
306
307
EXAMPLES::
308
309
sage: octave.set('x', '2') #optional -- requires Octave
310
sage: octave.get('x') #optional -- requires Octave
311
' 2'
312
"""
313
s = self.eval('%s'%var)
314
i = s.find('=')
315
return s[i+1:]
316
317
def clear(self, var):
318
"""
319
Clear the variable named var.
320
321
EXAMPLES::
322
323
sage: octave.set('x', '2') #optional -- requires Octave
324
sage: octave.clear('x') #optional -- requires Octave
325
sage: octave.get('x') #optional -- requires Octave
326
"error: `x' undefined near line ... column 1"
327
"""
328
self.eval('clear %s'%var)
329
330
def console(self):
331
"""
332
Spawn a new Octave command-line session.
333
334
This requires that the optional octave program be installed and in
335
your PATH, but no optional Sage packages need be installed.
336
337
EXAMPLES::
338
339
sage: octave_console() # not tested
340
GNU Octave, version 2.1.73 (i386-apple-darwin8.5.3).
341
Copyright (C) 2006 John W. Eaton.
342
...
343
octave:1> 2+3
344
ans = 5
345
octave:2> [ctl-d]
346
347
Pressing ctrl-d exits the octave console and returns you to Sage.
348
octave, like Sage, remembers its history from one session to
349
another.
350
"""
351
octave_console()
352
353
def version(self):
354
"""
355
Return the version of Octave.
356
357
OUTPUT: string
358
359
EXAMPLES::
360
361
sage: octave.version() # optional -- requires Octave; random output depending on version
362
'2.1.73'
363
"""
364
return octave_version()
365
366
def solve_linear_system(self, A, b):
367
"""
368
Use octave to compute a solution x to A\*x = b, as a list.
369
370
INPUT:
371
372
373
- ``A`` - mxn matrix A with entries in QQ or RR
374
375
- ``b`` - m-vector b entries in QQ or RR (resp)
376
377
378
OUTPUT: An list x (if it exists) which solves M\*x = b
379
380
EXAMPLES::
381
382
sage: M33 = MatrixSpace(QQ,3,3)
383
sage: A = M33([1,2,3,4,5,6,7,8,0])
384
sage: V3 = VectorSpace(QQ,3)
385
sage: b = V3([1,2,3])
386
sage: octave.solve_linear_system(A,b) # optional -- requires Octave (and output is slightly random in low order bits)
387
[-0.33333299999999999, 0.66666700000000001, -3.5236600000000002e-18]
388
389
AUTHORS:
390
391
- David Joyner and William Stein
392
"""
393
m = A.nrows()
394
n = A.ncols()
395
if m != len(b):
396
raise ValueError, "dimensions of A and b must be compatible"
397
from sage.matrix.all import MatrixSpace
398
from sage.rings.all import QQ
399
MS = MatrixSpace(QQ,m,1)
400
b = MS(list(b)) # converted b to a "column vector"
401
sA = self.sage2octave_matrix_string(A)
402
sb = self.sage2octave_matrix_string(b)
403
self.eval("a = " + sA )
404
self.eval("b = " + sb )
405
soln = octave.eval("c = a \\ b")
406
soln = soln.replace("\n\n ","[")
407
soln = soln.replace("\n\n","]")
408
soln = soln.replace("\n",",")
409
sol = soln[3:]
410
return eval(sol)
411
412
413
def sage2octave_matrix_string(self, A):
414
"""
415
Return an octave matrix from a Sage matrix.
416
417
INPUT: A Sage matrix with entries in the rationals or reals.
418
419
OUTPUT: A string that evaluates to an Octave matrix.
420
421
EXAMPLES::
422
423
sage: M33 = MatrixSpace(QQ,3,3)
424
sage: A = M33([1,2,3,4,5,6,7,8,0])
425
sage: octave.sage2octave_matrix_string(A) # optional -- requires Octave
426
'[1, 2, 3; 4, 5, 6; 7, 8, 0]'
427
428
AUTHORS:
429
430
- David Joyner and William Stein
431
"""
432
return str(A.rows()).replace('), (', '; ').replace('(', '').replace(')','')
433
434
def de_system_plot(self, f, ics, trange):
435
r"""
436
Plots (using octave's interface to gnuplot) the solution to a
437
`2\times 2` system of differential equations.
438
439
INPUT:
440
441
442
- ``f`` - a pair of strings representing the
443
differential equations; The independent variable must be called x
444
and the dependent variable must be called y.
445
446
- ``ics`` - a pair [x0,y0] such that x(t0) = x0, y(t0)
447
= y0
448
449
- ``trange`` - a pair [t0,t1]
450
451
452
OUTPUT: a gnuplot window appears
453
454
EXAMPLES::
455
456
sage: octave.de_system_plot(['x+y','x-y'], [1,-1], [0,2]) # not tested -- does this actually work (on OS X it fails for me -- William Stein, 2007-10)
457
458
This should yield the two plots `(t,x(t)), (t,y(t))` on the
459
same graph (the `t`-axis is the horizontal axis) of the
460
system of ODEs
461
462
.. math::
463
464
x' = x+y, x(0) = 1;\qquad y' = x-y, y(0) = -1, \quad\text{for}\quad 0 < t < 2.
465
"""
466
eqn1 = f[0].replace('x','x(1)').replace('y','x(2)')
467
eqn2 = f[1].replace('x','x(1)').replace('y','x(2)')
468
fcn = "function xdot = f(x,t) xdot(1) = %s; xdot(2) = %s; endfunction"%(eqn1, eqn2)
469
self.eval(fcn)
470
x0_eqn = "x0 = [%s; %s]"%(ics[0], ics[1])
471
self.eval(x0_eqn)
472
t_eqn = "t = linspace(%s, %s, 200)'"%(trange[0], trange[1])
473
self.eval(t_eqn)
474
x_eqn = 'x = lsode("f",x0,t);'
475
self.eval(x_eqn)
476
self.eval("plot(t,x)")
477
478
def _object_class(self):
479
"""
480
EXAMPLES::
481
482
sage: octave._object_class()
483
<class 'sage.interfaces.octave.OctaveElement'>
484
"""
485
return OctaveElement
486
487
488
class OctaveElement(ExpectElement):
489
def _matrix_(self, R):
490
r"""
491
Return Sage matrix from this octave element.
492
493
EXAMPLES::
494
495
sage: A = octave('[1,2;3,4]') # optional -- requires Octave
496
sage: matrix(ZZ, A) # optional -- requires Octave
497
[1 2]
498
[3 4]
499
sage: A = octave('[1,2;3,4.5]') # optional -- requires Octave
500
sage: matrix(RR, A) # optional -- requires Octave
501
[1.00000000000000 2.00000000000000]
502
[3.00000000000000 4.50000000000000]
503
"""
504
from sage.matrix.all import MatrixSpace
505
s = str(self).strip()
506
v = s.split('\n ')
507
nrows = len(v)
508
if nrows == 0:
509
return MatrixSpace(R,0,0)(0)
510
ncols = len(v[0].split())
511
M = MatrixSpace(R, nrows, ncols)
512
v = sum([[x for x in w.split()] for w in v], [])
513
return M(v)
514
515
516
# An instance
517
octave = Octave(script_subdirectory='user')
518
519
def reduce_load_Octave():
520
"""
521
EXAMPLES::
522
523
sage: from sage.interfaces.octave import reduce_load_Octave
524
sage: reduce_load_Octave()
525
Octave
526
"""
527
return octave
528
529
530
import os
531
def octave_console():
532
"""
533
Spawn a new Octave command-line session.
534
535
This requires that the optional octave program be installed and in
536
your PATH, but no optional Sage packages need be installed.
537
538
EXAMPLES::
539
540
sage: octave_console() # not tested
541
GNU Octave, version 2.1.73 (i386-apple-darwin8.5.3).
542
Copyright (C) 2006 John W. Eaton.
543
...
544
octave:1> 2+3
545
ans = 5
546
octave:2> [ctl-d]
547
548
Pressing ctrl-d exits the octave console and returns you to Sage.
549
octave, like Sage, remembers its history from one session to
550
another.
551
"""
552
os.system('octave')
553
554
555
def octave_version():
556
"""
557
Return the version of Octave installed.
558
559
EXAMPLES::
560
561
sage: octave_version() # optional -- requires Octave; and output is random
562
'2.9.12'
563
"""
564
return str(octave('version')).strip()
565
566
567