pure-octave

Version 0.9, March 06, 2017

Albert Graef <aggraef@gmail.com>

A Pure interface to GNU Octave.

Introduction

This is an Octave module for the Pure programming language, based on Paul Kienzle’s octave_embed which allows Octave to be embedded in other languages. It allows you to execute arbitrary Octave commands and Octave functions from Pure.

Copying

pure-octave is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

pure-octave is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Please see the accompanying COPYING file for the precise license terms. The GPL can also be read online at http://www.gnu.org/licenses/.

Installation

Get the latest source from https://bitbucket.org/purelang/pure-lang/downloads/pure-octave-0.9.tar.gz.

Run make to compile the module and make install (as root) to install it in the Pure library directory. This requires GNU make, and of course you need to have both Pure and Octave installed (including Octave’s mkoctfile utility and the corresponding header files and libraries).

make tries to guess your Pure installation directory and platform-specific setup. If it gets this wrong, you can set some variables manually. In particular, make install prefix=/usr sets the installation prefix. Please see the Makefile for details.

This release of pure-octave has been tested and is known to work with Octave 3.6.2, 3.8, 4.0 and (development version) 4.3. Older versions might require some fiddling with the sources to get the embedded Octave interface working.

NOTE: At the time of this writing, the embedded interpreter is broken with Octave 4.2, so you’ll either have to stick to Octave 4.0 for the time being, or use the 4.3 development version.

Basic Usage

Import this module into your Pure scripts as follows:

using octave;

This will add an embedded instance of the Octave interpreter to your program. (You can import this module as often as you want, but there’s always only one instance of Octave in each process.)

octave_eval s
Executes arbitrary Octave code.
> octave_eval "eig([1 2;3 4])";
ans =

  -0.37228
   5.37228

0

This prints the result on stdout and returns a result code (zero if everything went fine). To suppress the printing of the result, simply terminate the Octave statement with a semicolon:

> octave_eval "eig([1 2;3 4]);";
0
octave_set var val, octave_get var
Set and get global variables in the Octave interpreter.

This allows you to define values to be used when evaluating Octave code, and to transfer results back to Pure. However, before such globals can be accessed in Octave, you must explicitly declare them as globals:

> octave_eval "global x y ans";
0

Now you can use octave_set and octave_get to transfer values between Pure and Octave as follows:

> octave_set "x" {1.0,2.0;3.0,4.0};
{1.0,2.0;3.0,4.0}
> octave_eval "eig(x);";
0
> octave_get "ans";
{-0.372281323269014;5.37228132326901}

Note that the most recent result can always be accessed through Octave’s ans variable. You can also use an explicit variable definition as follows:

> octave_eval "y = eig(x);";
0
> octave_get "y";
{-0.372281323269014;5.37228132326901}

Direct Function Calls

octave_call fun n args
Call an octave function in a direct fashion. fun denotes the name of the function, n the number of function results and args the function arguments.
> let x = {1.0,2.0;3.0,4.0};
> octave_call "eig" 1 x;
{-0.372281323269014;5.37228132326901}

Note the second argument, which denotes the desired number of return values. This will usually be 1 (or 0 if you don’t care about the result), but some Octave functions may return a variable number of results, depending on how they’re called. Multiple values are returned as tuples in Pure:

> octave_call "eig" 2 x;
{-0.824564840132394,-0.415973557919284;0.565767464968992,-0.909376709132124},
{-0.372281323269014,0.0;0.0,5.37228132326901}

Multiple arguments are also specified as a tuple:

> octave_call "norm" 1 (x, 2);
5.46498570421904
> octave_call "norm" 1 (x, 1);
6.0

Instead of a function name, you can also specify the function to be called using a special kind of Octave object, a function value. These are returned, e.g., by Octave’s str2func and inline builtins. For your convenience, pure-octave provides a frontend to these builtins, the octave_func function, which lets you specify an Octave function in one of two ways:

octave_func name
Returns the Octave function with the given name. This works like Octave’s str2func builtin.
octave_func expr
Returns an “inline” function, where expr is an Octave expression (as a string) describing the function value. This works like Octave’s inline builtin. Instead of just an Octave expression, you can also specify a tuple consisting of the inline expression and the parameter names. (Otherwise the parameters are determined automatically, see the description of the inline function in the Octave manual for details.)

Note that inline functions allow you to call stuff that is not an Octave function and hence cannot be specified directly in octave_call, such as an operator. Examples:

> let eig = octave_func "eig";
> let mul = octave_func "x*y";
> octave_call eig 1 (octave_call mul 1 (x,x));
{0.138593383654928;28.8614066163451}
> let add = octave_func ("x+y","x","y");
> octave_call add 1 (x,x);
{2.0,4.0;6.0,8.0}

Data Conversions

As shown above, the octave_set, octave_get and octave_call functions convert Pure data to corresponding Octave values and vice versa. Octave scalars and matrices of boolean, integer, double, complex and character data are all directly supported by this interface, and are mapped to the corresponding Pure data types in a straightforward manner (scalars to scalars, matrices to matrices and strings to strings). Note that in any case these conversions create copies of the data, so modifying, say, an Octave matrix received via octave_get in Pure only affects the Pure copy of the matrix and leaves the original Octave matrix unchanged.

Octave’s higher-dimensional numeric arrays, cell arrays and structures are not natively supported by the interface, but are implemented using special conversion hooks defined in the octave.pure module (see the __pure2oct__ and __oct2pure__ functions in octave.pure). This simplifies the implementation and makes these conversions customizable if the need arises. It also makes it possible to extend the interface for further special data structures in the future. Please check the octave.pure module for details. It’s possible to disable these custom conversions with the octave_converters function:

octave_converters flag
Enable or disable custom data conversions between Pure and Octave. The given flag must be a truth value (zero means disable, any nonzero value enable). The function returns the previous value of the flag.

Octave objects which are neither handled natively by the interface nor through the auxiliary converters (if enabled) are just passed through as is, in the form of a cooked pointer to an Octave value which frees itself when garbage-collected. This allows these objects to be passed around freely, but you can’t inspect or modify them in Pure. This applies, in particular, to Octave function objects, see Direct Function Calls. You can check for such objects with the octave_valuep predicate:

octave_valuep x
Check for Octave value pointers.
> let eig = octave_func "eig";
> eig; octave_valuep eig;
#<pointer 0x230dba0>
1

Such Octave value pointers can be used freely whereever an Octave value is needed (i.e., in invocations of octave_set and octave_call).

You should also note the following:

Calling Back Into Pure

The embedded Octave interpreter provides one special builtin, the pure_call function which can be used to call any function defined in the executing Pure script from Octave. For instance:

> even m::matrix = {~(int x mod 2) | x=m};
> octave_eval "pure_call('even', 1:12)";
ans =

  0  1  0  1  0  1  0  1  0  1  0  1

0

Here’s the description of the pure_call function, as it is printed with Octave’s help command:

`pure_call' is a built-in function

  RES = pure_call(NAME, ARG, ...)
  [RES, ...] = pure_call(NAME, ARG, ...)

  Execute the Pure function named NAME (a string) with the given arguments.
  The Pure function may return multiple results as a tuple. Example:
  pure_call('succ', 99) => 100.

Gnuplot Interface

Octave has a comprehensive plotting interface based on Gnuplot. To make the plotting capabilities available in a convenient form in Pure, the distribution includes an additional gnuplot.pure module which provides simple wrappers of the most important plotting functions. Please check gnuplot.pure for details. For instance, here are a few simple plotting commands:

using gnuplot;
using namespace gnuplot;

sombrero(); // sample "sombrero" plot (3d)
popup();    // show the plot window
peaks 25;   // another sample 3d plot
refresh();  // update the window
popdn();    // hide the plot window
print "plot.eps"; // print the plot to an encapsulated PostScript file

Note that most of the operations are in their own gnuplot namespace, so we used a using namespace declaration for convenience here. The following example does the “sombrero” plot again, but shows some of the explicit plotting commands and helper functions to generate the data:

using math;
let u = linspace (-8, 8, 41);
let x,y = meshgrid2 u;
let z = {sin r/r | r = {sqrt (x^2+y^2)+eps() | x,y = zip x y}};
mesh (u, u, z);
popup();

Note the commands that are needed to actually show the plot window and update its contents after doing each plot. Octave normally handles this automatically in its command loop, but since the embedded Octave interpreter doesn’t have an interactive command line, you’ll have to take care of this yourself when using this module.

Also note that there doesn’t seem to be a direct way to specify the default output terminal in the Octave gnuplot interface, so if you need to do this then you’ll have to set the GNUTERM environment variable as described in the gnuplot manual page.

Caveats and Notes

Directly embedding Octave in Pure programs is convenient because it allows easy exchange of data between Pure and Octave, and you can also call Octave functions directly from Pure and vice versa. However, it also comes at a cost. A default build of Octave pulls in quite a few dependencies of its own which might conflict with other modules loaded in a Pure script. Specifically, we have found that older Octave versions may give problems with third-party graphics libraries such as VTK, if used in the same program as Octave. (These seem to be fixed in the latest Octave and VTK versions, however.)