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