CoCalc Shared Filesoctave.py
Authors: David Cyganski, Bill Page
Views : 15
Description: Improved version of the octave interface.
1r"""
2Interface to GNU Octave
3
4GNU Octave is a free software (GPL) MATLAB-like program with numerical
5routines for integrating, solving systems of equations, special
6functions, and solving (numerically) differential equations. Please see
7http://octave.org/ for more details.
8
9The commands in this section only work if you have the optional
10"octave" interpreter installed and available in your PATH. It's not
11necessary to install any special Sage packages.
12
13EXAMPLES::
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
22LOG: - creation (William Stein) - ? (David Joyner, 2005-12-18) -
23Examples (David Joyner, 2005-01-03)
24
25Computation of Special Functions
26--------------------------------
27
28Octave implements computation of the following special functions
29(see the maxima and gp interfaces for even more special
30functions)::
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
59For 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
90The Octave interface reads in even very long input (using files) in
91a 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
97Note that actually reading a back out takes forever. This *must*
98be fixed as soon as possible, see :trac:940.
99
100Tutorial
101--------
102
103EXAMPLES::
104
105    sage: octave('4+10')              # optional - octave
106    14
107    sage: octave('date')              # optional - octave; random output
108    18-Oct-2007
109    sage: octave('5*10 + 6')          # optional - octave
110    56
111    sage: octave('(6+6)/3')           # optional - octave
112    4
113    sage: octave('9')^2               # optional - octave
114    81
115    sage: a = octave(10); b = octave(20); c = octave(30)    # optional - octave
116    sage: avg = (a+b+c)/3             # optional - octave
117    sage: avg                         # optional - octave
118    20
119    sage: parent(avg)                 # optional - octave
120    Octave
121
122::
123
124    sage: my_scalar = octave('3.1415')       # optional - octave
125    sage: my_scalar                          # optional - octave
126    3.1415
127    sage: my_vector1 = octave('[1,5,7]')     # optional - octave
128    sage: my_vector1                         # optional - octave
129    1     5     7
130    sage: my_vector2 = octave('[1;5;7]')     # optional - octave
131    sage: my_vector2                         # optional - octave
132    1
133    5
134    7
135    sage: my_vector1 * my_vector2            # optional - octave
136    75
137"""
138
139#*****************************************************************************
140#       Copyright (C) 2005 William Stein <[email protected]>
141#
143#
144#    This code is distributed in the hope that it will be useful,
145#    but WITHOUT ANY WARRANTY; without even the implied warranty of
146#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
147#    General Public License for more details.
148#
149#  The full text of the GPL is available at:
150#
152#*****************************************************************************
153
154import os
155from expect import Expect, ExpectElement
156from sage.misc.misc import verbose
157
158
159class Octave(Expect):
160    r"""
161    Interface to the Octave interpreter.
162
163    EXAMPLES::
164
165        sage: octave.eval("a = [ 1, 1, 2; 3, 5, 8; 13, 21, 33 ]")    # optional - octave
166        'a =\n\n 1 1 2\n 3 5 8\n 13 21 33\n\n'
167        sage: octave.eval("b = [ 1; 3; 13]")                         # optional - octave
168        'b =\n\n 1\n 3\n 13\n\n'
169        sage: octave.eval("c=a \\ b") # solves linear equation: a*c = b  # optional - octave; random output
170        'c =\n\n 1\n 7.21645e-16\n -7.21645e-16\n\n'
171        sage: octave.eval("c")                                 # optional - octave; random output
172        'c =\n\n 1\n 7.21645e-16\n -7.21645e-16\n\n'
173    """
174
175    def __init__(self, maxread=100, script_subdirectory=None, logfile=None, server=None, server_tmpdir=None,
176                 seed=None):
177        """
178        EXAMPLES::
179
181            True
182        """
183        Expect.__init__(self,
184                        name = 'octave',
185                        # We want the prompt sequence to be unique to avoid confusion with syntax error messages containing >>>
186                        prompt = 'octave\:\d+> ',
187                        # We don't want any pagination of output
188                        command = "sage-native-execute octave --no-line-editing --silent --eval 'PS2(PS1());more off' --persist",
190                        server = server,
191                        server_tmpdir = server_tmpdir,
192                        script_subdirectory = script_subdirectory,
193                        restart_on_ctrlc = False,
194                        verbose_start = False,
195                        logfile = logfile,
196                        eval_using_file_cutoff=100)
197        self._seed = seed
198
199    def set_seed(self, seed=None):
200        """
201        Sets the seed for the random number generator
202        for this octave interpreter.
203
204        EXAMPLES::
205
206            sage: o = Octave() # optional - octave
207            sage: o.set_seed(1) # optional - octave
208            1
209            sage: [o.rand() for i in range(5)] # optional - octave
210            [ 0.134364,  0.847434,  0.763775,  0.255069,  0.495435]
211        """
212        if seed is None:
213            seed = self.rand_seed()
214        self.eval("rand('state',%d)" % seed)
215        self._seed = seed
216        return seed
217
218    def __reduce__(self):
219        """
220        EXAMPLES::
221
222            sage: octave.__reduce__()
223            (<function reduce_load_Octave at 0x...>, ())
224        """
226
228        """
229        EXAMPLES::
230
231            sage: filename = tmp_filename()
233            'source("...");'
234        """
235        return 'source("%s");'%filename
236
237    def _quit_string(self):
238        """
239        EXAMPLES::
240
241            sage: octave._quit_string()
242            'quit;'
243        """
244        return 'quit;'
245
246    def _install_hints(self):
247        """
248        Returns hints on how to install Octave.
249
250        EXAMPLES::
251
252            sage: print octave._install_hints()
253            You must get ...
254        """
255        return """
256        You must get the program "octave" in order to use Octave
258                http://www.gnu.org/software/octave/
259
260        LINUX / WINDOWS (colinux):
261           Do apt-get install octave as root on your machine
262           (or, in Windows, in the colinux console).
263
264        OS X:
265           * This website has links to binaries for OS X PowerPC
266             and OS X Intel builds of the latest version of Octave:
267                     http://hpc.sourceforge.net/
268             Once you get the tarball from there, go to the / directory
269             and type
270                     tar zxvf octave-intel-bin.tar.gz
271             to extract it to usr/local/...   Make sure /usr/local/bin
272             is in your PATH.  Then type "octave" and verify that
273             octave starts up.
274           * Darwin ports and fink have Octave as well.
275        """
276    def _eval_line(self, line, reformat=True, allow_use_file=False,
277                   wait_for_prompt=True, restart_if_needed=False):
278        """
279        EXAMPLES::
280
281            sage: print octave._eval_line('2+2')  #optional - octave
282              ans =  4
283        """
284        if not wait_for_prompt:
285            return Expect._eval_line(self, line)
286        if line == '':
287            return ''
288        if self._expect is None:
289            self._start()
290        if allow_use_file and len(line)>3000:
291            return self._eval_line_using_file(line)
292        try:
293            E = self._expect
294            # debug
295            # self._synchronize(cmd='1+%s\n')
296            verbose("in = '%s'"%line,level=3)
297            E.sendline(line)
298            E.expect(self._prompt)
299            out = E.before
300            # debug
301            verbose("out = '%s'"%out,level=3)
302        except EOF:
303            if self._quit_string() in line:
304                return ''
305        except KeyboardInterrupt:
306            self._keyboard_interrupt()
307        if reformat:
308            if 'syntax error' in out:
309                raise SyntaxError(out)
310        out = "\n".join(out.splitlines()[1:])
311        return out
312
313    def _keyboard_interrupt(self):
314        print "CntrlC: Interrupting %s..."%self
315        if self._restart_on_ctrlc:
316            try:
317                self._expect.close(force=1)
318            except pexpect.ExceptionPexpect as msg:
319                raise pexpect.ExceptionPexpect( "THIS IS A BUG -- PLEASE REPORT. This should never happen.\n" + msg)
320            self._start()
321            raise KeyboardInterrupt("Restarting %s (WARNING: all variables defined in previous session are now invalid)"%self)
322        else:
323            self._expect.send('\003') # control-c
324            #self._expect.expect(self._prompt)
325            #self._expect.expect(self._prompt)
326            raise KeyboardInterrupt("Ctrl-c pressed while running %s"%self)
327
328    def quit(self, verbose=False):
329        """
330        EXAMPLES::
331
332            sage: o = Octave()
333            sage: o._start()    # optional - octave
334            sage: o.quit(True)  # optional - octave
335            Exiting spawned Octave process.
336        """
337        # Don't bother, since it just hangs in some cases, and it
338        # isn't necessary, since octave behaves well with respect
339        # to signals.
340        if not self._expect is None:
341            if verbose:
342                print "Exiting spawned %s process." % self
343        return
344
345    def _start(self):
346        """
347        Starts the Octave process.
348
349        EXAMPLES::
350
351            sage: o = Octave()    # optional - octave
352            sage: o.is_running()  # optional - octave
353            False
354            sage: o._start()      # optional - octave
355            sage: o.is_running()  # optional - octave
356            True
357        """
358        Expect._start(self)
359        self.eval("page_screen_output=0;")
360        self.eval("format none;")
361        # set random seed
362        self.set_seed(self._seed)
363
364    def _equality_symbol(self):
365        """
366        EXAMPLES::
367
368            sage: octave('0 == 1')  # optional - octave
369             0
370            sage: octave('1 == 1')  # optional - octave
371             1
372        """
373        return '=='
374
375    def _true_symbol(self):
376        """
377        EXAMPLES::
378
379            sage: octave('1 == 1')  # optional - octave
380             1
381        """
382        return '1'
383
384    def _false_symbol(self):
385        """
386        EXAMPLES::
387
388            sage: octave('0 == 1')  # optional - octave
389             0
390        """
391        return '0'
392
393    def set(self, var, value):
394        """
395        Set the variable var to the given value.
396
397        EXAMPLES::
398
399            sage: octave.set('x', '2') # optional - octave
400            sage: octave.get('x') # optional - octave
401            ' 2'
402        """
403        cmd = '%s=%s;'%(var,value)
404        out = self.eval(cmd)
405        if out.find("error") != -1 or out.find("Error") != -1:
406            raise TypeError("Error executing code in Octave\nCODE:\n\t%s\nOctave ERROR:\n\t%s"%(cmd, out))
407
408    def get(self, var):
409        """
410        Get the value of the variable var.
411
412        EXAMPLES::
413
414            sage: octave.set('x', '2') # optional - octave
415            sage: octave.get('x') # optional - octave
416            ' 2'
417        """
418        s = self.eval('%s'%var)
419        i = s.find('=')
420        return s[i+1:]
421
422    def clear(self, var):
423        """
424        Clear the variable named var.
425
426        EXAMPLES::
427
428            sage: octave.set('x', '2') # optional - octave
429            sage: octave.clear('x')    # optional - octave
430            sage: octave.get('x')      # optional - octave
431            "error: 'x' undefined near line ... column 1"
432        """
433        self.eval('clear %s'%var)
434
435    def console(self):
436        """
437        Spawn a new Octave command-line session.
438
439        This requires that the optional octave program be installed and in
440        your PATH, but no optional Sage packages need be installed.
441
442        EXAMPLES::
443
444            sage: octave_console()         # not tested
445            GNU Octave, version 2.1.73 (i386-apple-darwin8.5.3).
446            Copyright (C) 2006 John W. Eaton.
447            ...
448            octave:1> 2+3
449            ans = 5
450            octave:2> [ctl-d]
451
452        Pressing ctrl-d exits the octave console and returns you to Sage.
453        octave, like Sage, remembers its history from one session to
454        another.
455        """
456        octave_console()
457
458    def version(self):
459        """
460        Return the version of Octave.
461
462        OUTPUT: string
463
464        EXAMPLES::
465
466            sage: octave.version()   # optional - octave; random output depending on version
467            '2.1.73'
468        """
469        return octave_version()
470
471    def solve_linear_system(self, A, b):
472        r"""
473        Use octave to compute a solution x to A\*x = b, as a list.
474
475        INPUT:
476
477        - A -- mxn matrix A with entries in \QQ or \RR
478
479        - b -- m-vector b entries in \QQ or \RR (resp)
480
481        OUTPUT: A list x (if it exists) which solves M\*x = b
482
483        EXAMPLES::
484
485            sage: M33 = MatrixSpace(QQ,3,3)
486            sage: A   = M33([1,2,3,4,5,6,7,8,0])
487            sage: V3  = VectorSpace(QQ,3)
488            sage: b   = V3([1,2,3])
489            sage: octave.solve_linear_system(A,b)    # optional - octave (and output is slightly random in low order bits)
490            [-0.33333299999999999, 0.66666700000000001, -3.5236600000000002e-18]
491
492        AUTHORS:
493
494        - David Joyner and William Stein
495        """
496        m = A.nrows()
497        if m != len(b):
498            raise ValueError("dimensions of A and b must be compatible")
499        from sage.matrix.all import MatrixSpace
500        from sage.rings.all import QQ
501        MS = MatrixSpace(QQ,m,1)
502        b  = MS(list(b)) # converted b to a "column vector"
503        sA = self.sage2octave_matrix_string(A)
504        sb = self.sage2octave_matrix_string(b)
505        self.eval("a = " + sA )
506        self.eval("b = " + sb )
507        soln = octave.eval("c = a \\ b")
508        soln = soln.replace("\n\n ","[")
509        soln = soln.replace("\n\n","]")
510        soln = soln.replace("\n",",")
511        sol  = soln[3:]
512        return eval(sol)
513
514
515    def sage2octave_matrix_string(self, A):
516        """
517        Return an octave matrix from a Sage matrix.
518
519        INPUT: A Sage matrix with entries in the rationals or reals.
520
521        OUTPUT: A string that evaluates to an Octave matrix.
522
523        EXAMPLES::
524
525            sage: M33 = MatrixSpace(QQ,3,3)
526            sage: A = M33([1,2,3,4,5,6,7,8,0])
527            sage: octave.sage2octave_matrix_string(A)   # optional - octave
528            '[1, 2, 3; 4, 5, 6; 7, 8, 0]'
529
530        AUTHORS:
531
532        - David Joyner and William Stein
533        """
534        return str(A.rows()).replace('), (', '; ').replace('(', '').replace(')','')
535
536    def de_system_plot(self, f, ics, trange):
537        r"""
538        Plots (using octave's interface to gnuplot) the solution to a
539        2\times 2 system of differential equations.
540
541        INPUT:
542
543
544        -  f - a pair of strings representing the
545           differential equations; The independent variable must be called x
546           and the dependent variable must be called y.
547
548        -  ics - a pair [x0,y0] such that x(t0) = x0, y(t0)
549           = y0
550
551        -  trange - a pair [t0,t1]
552
553
554        OUTPUT: a gnuplot window appears
555
556        EXAMPLES::
557
558            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)
559
560        This should yield the two plots (t,x(t)), (t,y(t)) on the
561        same graph (the t-axis is the horizontal axis) of the
562        system of ODEs
563
564        .. math::
565
566                       x' = x+y, x(0) = 1;\qquad y' = x-y, y(0) = -1,                     \quad\text{for}\quad 0 < t < 2.
567        """
568        eqn1 = f[0].replace('x','x(1)').replace('y','x(2)')
569        eqn2 = f[1].replace('x','x(1)').replace('y','x(2)')
570        fcn = "function xdot = f(x,t) xdot(1) = %s; xdot(2) = %s; endfunction"%(eqn1, eqn2)
571        self.eval(fcn)
572        x0_eqn = "x0 = [%s; %s]"%(ics[0], ics[1])
573        self.eval(x0_eqn)
574        t_eqn = "t = linspace(%s, %s, 200)'"%(trange[0], trange[1])
575        self.eval(t_eqn)
576        x_eqn = 'x = lsode("f",x0,t);'
577        self.eval(x_eqn)
578        self.eval("plot(t,x)")
579
580    def _object_class(self):
581        """
582        EXAMPLES::
583
584            sage: octave._object_class()
585            <class 'sage.interfaces.octave.OctaveElement'>
586        """
587        return OctaveElement
588
589
590octave_functions = set()
591
592def to_complex(octave_string, R):
593    r"""
594    Helper function to convert octave complex number
595
596    TESTS::
597
598        sage: from sage.interfaces.octave import to_complex
599        sage: to_complex('(0,1)', CDF)
600        1.0*I
601        sage: to_complex('(1.3231,-0.2)', CDF)
602        1.3231 - 0.2*I
603    """
604    real, imag = octave_string.strip('() ').split(',')
605    return R(float(real), float(imag))
606
607class OctaveElement(ExpectElement):
608    def _get_sage_ring(self):
609        r"""
610        TESTS::
611
612            sage: octave('1')._get_sage_ring()  # optional - octave
613            Real Double Field
614            sage: octave('I')._get_sage_ring()  # optional - octave
615            Complex Double Field
616            sage: octave('[]')._get_sage_ring() # optional - octave
617            Real Double Field
618        """
619        if self.isinteger():
620            import sage.rings.integer_ring
621            return sage.rings.integer_ring.ZZ
622        elif self.isreal():
623            import sage.rings.real_double
624            return sage.rings.real_double.RDF
625        elif self.iscomplex():
626            import sage.rings.complex_double
627            return sage.rings.complex_double.CDF
628        else:
629            raise TypeError("no Sage ring associated to this element.")
630
631    def __nonzero__(self):
632        r"""
633        Test whether this element is nonzero.
634
635        EXAMPLES::
636
637            sage: bool(octave('0'))                 # optional - octave
638            False
639            sage: bool(octave('[]'))                # optional - octave
640            False
641            sage: bool(octave('[0,0]'))             # optional - octave
642            False
643            sage: bool(octave('[0,0,0;0,0,0]'))     # optional - octave
644            False
645
646            sage: bool(octave('0.1'))               # optional - octave
647            True
648            sage: bool(octave('[0,1,0]'))           # optional - octave
649            True
650            sage: bool(octave('[0,0,-0.1;0,0,0]'))  # optional - octave
651            True
652        """
653        return str(self) != ' [](0x0)' and any(x != '0' for x in str(self).split())
654
655    def _matrix_(self, R=None):
656        r"""
657        Return Sage matrix from this octave element.
658
659        EXAMPLES::
660
661            sage: A = octave('[1,2;3,4.5]')     # optional - octave
662            sage: matrix(A)                     # optional - octave
663            [1.0 2.0]
664            [3.0 4.5]
665            sage: _.base_ring()                 # optional - octave
666            Real Double Field
667
668            sage: A = octave('[I,1;-1,0]')      # optional - octave
669            sage: matrix(A)                     # optional - octave
670            [1.0*I   1.0]
671            [ -1.0   0.0]
672            sage: _.base_ring()                 # optional - octave
673            Complex Double Field
674
675            sage: A = octave('[1,2;3,4]')       # optional - octave
676            sage: matrix(ZZ, A)                 # optional - octave
677            [1 2]
678            [3 4]
679            sage: A = octave('[1,2;3,4.5]')     # optional - octave
680            sage: matrix(RR, A)                 # optional - octave
681            [1.00000000000000 2.00000000000000]
682            [3.00000000000000 4.50000000000000]
683        """
684        oc = self.parent()
685        if not self.ismatrix():
686            raise TypeError('not an octave matrix')
687        if R is None:
688            R = self._get_sage_ring()
689
690        s = str(self).strip('\n ')
691        w = [u.strip().split(' ') for u in s.split('\n')]
692        nrows = len(w)
693        ncols = len(w[0])
694
695        if self.iscomplex():
696            w = [[to_complex(x,R) for x in row] for row in w]
697
698        from sage.matrix.all import MatrixSpace
699        s = str(self).strip()
700        v = s.split('\n ')
701        nrows = len(v)
702        if nrows == 0:
703            return MatrixSpace(R,0,0)(0)
704        ncols = len(v[0].split())
705        M = MatrixSpace(R, nrows, ncols)
706        v = sum([[x for x in w.split()] for w in v], [])
707        return M(v)
708
709    def _vector_(self, R=None):
710        r"""
711        Return Sage vector from this octave element.
712
713        EXAMPLES::
714
715            sage: A = octave('[1,2,3,4]')       # optional - octave
716            sage: vector(ZZ, A)                 # optional - octave
717            (1, 2, 3, 4)
718            sage: A = octave('[1,2.3,4.5]')     # optional - octave
719            sage: vector(A)                     # optional - octave
720            (1.0, 2.3, 4.5)
721            sage: A = octave('[1,I]')           # optional - octave
722            sage: vector(A)                     # optional - octave
723            (1.0, 1.0*I)
724        """
725        oc = self.parent()
726        if not self.isvector():
727            raise TypeError('not an octave vector')
728        if R is None:
729            R = self._get_sage_ring()
730
731        s = str(self).strip('\n ')
732        w = s.strip().split(' ')
733        nrows = len(w)
734
735        if self.iscomplex():
736            w = [to_complex(x, R) for x in w]
737
738        from sage.modules.free_module import FreeModule
739        return FreeModule(R, nrows)(w)
740
741    def _scalar_(self):
742        """
743        Return Sage scalar from this octave element.
744
745        EXAMPLES::
746
747            sage: A = octave('2833')      # optional - octave
748            sage: As = A.sage(); As       # optional - octave
749            2833.0
750            sage: As.parent()             # optional - octave
751            Real Double Field
752
753            sage: B = sqrt(A)             # optional - octave
754            sage: Bs = B.sage(); Bs       # optional - octave
755            53.2259
756            sage: Bs.parent()             # optional - octave
757            Real Double Field
758
759            sage: C = sqrt(-A)            # optional - octave
760            sage: Cs = C.sage(); Cs       # optional - octave
761            53.2259*I
762            sage: Cs.parent()             # optional - octave
763            Complex Double Field
764        """
765        if not self.isscalar():
766            raise TypeError("not an octave scalar")
767
768        R = self._get_sage_ring()
769        if self.iscomplex():
771        else:
772            return R(str(self))
773
774    def _sage_(self):
775        """
776        Try to parse the octave object and return a sage object.
777
778        EXAMPLES::
779
780            sage: A = octave('2833')           # optional - octave
781            sage: A.sage()                     # optional - octave
782            2833.0
783            sage: B = sqrt(A)                  # optional - octave
784            sage: B.sage()                     # optional - octave
785            53.2259
786            sage: C = sqrt(-A)                 # optional - octave
787            sage: C.sage()                     # optional - octave
788            53.2259*I
789            sage: A = octave('[1,2,3,4]')      # optional - octave
790            sage: A.sage()                     # optional - octave
791            (1.0, 2.0, 3.0, 4.0)
792            sage: A = octave('[1,2.3,4.5]')    # optional - octave
793            sage: A.sage()                     # optional - octave
794            (1.0, 2.3, 4.5)
795            sage: A = octave('[1,2.3+I,4.5]')  # optional - octave
796            sage: A.sage()                     # optional - octave
797            (1.0, 2.3 + 1.0*I, 4.5)
798        """
799        if self.isscalar():
800            return self._scalar_()
801        elif self.isvector():
802            return self._vector_()
803        elif self.ismatrix():
804            return self._matrix_()
805        else:
806            raise NotImplementedError('octave type is not recognized')
807
808# An instance
809octave = Octave()
810
812    """
813    EXAMPLES::
814
815        sage: from sage.interfaces.octave import reduce_load_Octave
817        Octave
818    """
819    return octave
820
821
822def octave_console():
823    """
824    Spawn a new Octave command-line session.
825
826    This requires that the optional octave program be installed and in
827    your PATH, but no optional Sage packages need be installed.
828
829    EXAMPLES::
830
831        sage: octave_console()         # not tested
832        GNU Octave, version 2.1.73 (i386-apple-darwin8.5.3).
833        Copyright (C) 2006 John W. Eaton.
834        ...
835        octave:1> 2+3
836        ans = 5
837        octave:2> [ctl-d]
838
839    Pressing ctrl-d exits the octave console and returns you to Sage.
840    octave, like Sage, remembers its history from one session to
841    another.
842    """
843    os.system('octave')
844
845
846def octave_version():
847    """
848    Return the version of Octave installed.
849
850    EXAMPLES::
851
852        sage: octave_version()    # optional - octave; and output is random
853        '2.9.12'
854    """
855    return str(octave('version')).strip()
856