Octave is a high-level language intended for numerical programming that is mostly compatible with MATLAB. More information can be found at octave.org.
The Octave documentation is preliminary and is intended to give only a cursory introduction to using the module. You should (at a minimum) also read the SWIG documentation that is not specific to Octave. (also note, some of the early sections here are adapted from the Lua docs).
For now, the best way to find information about how to use the Octave module is to look at the code itself, test-suite, and examples. There are a dozen or so examples in the Examples/octave directory, and hundreds in the test suite (Examples/test-suite and Examples/test-suite/octave).
The bulk of the Octave-specific wrapper generator code is in Source/Modules/octave.cxx. The runtime components are in Lib/octave, and in particular Lib/octave/octrun.swg.
The current SWIG implemention is based on Octave 2.9.12. Support for other versions (in particular the recent 3.0) has not been tested, nor has support for any OS other than Linux.
Let's start with a very simple SWIG interface file:
%module example
%{
#include "example.h"
%}
int gcd(int x, int y);
extern double Foo; To build an Octave module, run SWIG using the -octave option. The -c++ option is required (for now) as Octave itself is written in C++ and thus the wrapper code must also be.
$ swig -octave -c++ example.i
This creates a C/C++ source file example_wrap.cxx. The generated C++ source file contains the low-level wrappers that need to be compiled and linked with the rest of your C/C++ application (in this case, the gcd implementation) to create an extension module.
The swig command line has a number of options you can use, like to redirect it's output. Use swig --help to learn about these.
Octave modules are DLLs/shared objects having the ".oct" suffix. Building an oct file is usually done with the mkoctfile command (either within Octave itself, or from the shell). For example,
$ swig -octave -c++ example.i -o example_wrap.cxx $ mkoctfile example_wrap.cxx example.c
where example.c is the file containing the gcd() implementation.
mkoctfile can also be used to extract the build parameters required to invoke the compiler and linker yourself. See the Octave manual and mkoctfile man page.
mkoctfile will produce example.oct, which contains the compiled extension module. Loading it into Octave is then a matter of invoking
octave:1> example
Assuming all goes well, you will be able to do this:
$ octave -q octave:1> example octave:2> example.gcd(4,6) ans = 2 octave:3> example.cvar.Foo ans = 3 octave:4> example.cvar.Foo=4; octave:5> example.cvar.Foo ans = 4
The SWIG module directive specifies the name of the Octave module. If you specify `module example', then in Octave everything in the module will be accessible under "example", as in the above example. When choosing a module name, make sure you don't use the same name as a built-in Octave command or standard module name.
When Octave is asked to invoke example, it will try to find the .m or .oct file that defines the function "example". It will thusly find example.oct, that upon loading will register all of the module's symbols.
Giving this function a parameter "global" will cause it to load all symbols into the global namespace in addition to the example namespace. For example:
$ octave -q
octave:1> example("global")
octave:2> gcd(4,6)
ans = 2
octave:3> cvar.Foo
ans = 3
octave:4> cvar.Foo=4;
octave:5> cvar.Foo
ans = 4
It is also possible to rename the module namespace with an assignment, as in:
octave:1> example; octave:2> c=example; octave:3> c.gcd(10,4) ans = 2
All global variables are put into the cvar namespace object. This is accessible either as my_module.cvar, or just cvar (if the module is imported into the global namespace).
One can also rename it by simple assignment, e.g.,
octave:1> some_vars = cvar;
Global functions are wrapped as new Octave built-in functions. For example,
%module example int fact(int n);
creates a built-in function example.fact(n) that works exactly like you think it does:
octave:1> example.fact(4) 24
Global variables are a little special in Octave. Given a global variable:
%module example
extern double Foo;
To expose variables, SWIG actually generates two functions, to get and set the value. In this case, Foo_set and Foo_set would be generated. SWIG then automatically calls these functions when you get and set the variable-- in the former case creating a local copy in the interpreter of the C variables, and in the latter case copying an interpreter variables onto the C variable.
octave:1> example; octave:2> c=example.cvar.Foo c = 3 octave:3> example.cvar.Foo=4; octave:4> c c = 3 octave:5> example.cvar.Foo ans = 4
If a variable is marked with the %immutable directive then any attempts to set this variable will cause an Octave error. Given a global variable:
%module example %immutable; extern double Foo; %mutable;
SWIG will allow the the reading of Foo but when a set attempt is made, an error function will be called.
octave:1> example octave:2> example.Foo=4 error: attempt to set immutable member variable error: assignment failed, or no method for `swig_type = scalar' error: evaluating assignment expression near line 2, column 12
It is possible to add new functions or variables to the module. This also allows the user to rename/remove existing functions and constants (but not linked variables, mutable or immutable). Therefore users are recommended to be careful when doing so.
octave:1> example; octave:2> example.PI=3.142; octave:3> example.PI ans = 3.1420
Because Octave doesn't really have the concept of constants, C/C++ constants are not really constant in Octave. They are actually just a copy of the value into the Octave interpreter. Therefore they can be changed just as any other value. For example given some constants:
%module example
%constant int ICONST=42;
#define SCONST "Hello World"
enum Days{SUNDAY,MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY};
This is 'effectively' converted into the following Octave code:
example.ICONST=42 example.SCONST="Hello World" example.SUNDAY=0 ....
C/C++ pointers are fully supported by SWIG. Furthermore, SWIG has no problem working with incomplete type information. Given a wrapping of the <file.h> interface: C/C++ pointers are fully supported by SWIG. Furthermore, SWIG has no problem working with incomplete type information. Given a wrapping of the <file.h> interface:
%module example FILE *fopen(const char *filename, const char *mode); int fputs(const char *, FILE *); int fclose(FILE *);
When wrapped, you will be able to use the functions in a natural way from Octave. For example:
octave:1> example;
octave:2> f=example.fopen("w","junk");
octave:3> example.fputs("Hello world",f);
octave:4> example.fclose(f);
Simply printing the value of a wrapped C++ type will print it's typename. E.g.,
octave:1> example;
octave:2> f=example.fopen("junk","w");
octave:3> f
f =
{
_p_FILE, ptr = 0x9b0cd00
} As the user of the pointer, you are responsible for freeing it, or closing any resources associated with it (just as you would in a C program). This does not apply so strictly to classes and structs (see below).
octave:1> example;
octave:2> f=example.fopen("not there","r");
error: value on right hand side of assignment is undefined
error: evaluating assignment expression near line 2, column 2 SWIG wraps C structures and C++ classes by creating type objects. When invoked as a function, they create a new object of their type. The structures/classes themselves are mapped to a native Octave type. This provides a very natural interface. For example,
struct Point{
int x,y;
};
is used as follows:
octave:1> example; octave:2> p=example.Point(); octave:3> p.x=3; octave:4> p.y=5; octave:5> p.x, p.y ans = 3 ans = 5
C++ classes are handled in a way identical to other modules.
Inheritance is handled in a way identical to other modules.
Pointers, references, values, and arrays are handled in the same way as other modules.
There are still some failing tests relating to global arrays.
Overloaded functions are supported, and handled as in other modules.
C++ operator overloading is supported, in a way similar to other modules.
SWIG types are represented in Octave by a special type called swig_ref (the full list of types can be listed with typeinfo(), and SWIG specific information can be extracted via swig_this(obj) and swig_type(obj)). This type supports all unary and binary operators between itself and all other types that exist in the system at module load time. When an operator is used (where one of the operands is a swig_ref), the runtime routes the call to either a member function of the given object, or to a global function whose named is derived from the types of the operands (either both or just the lhs or rhs). (... more details needed ...)
For example, if a and b are SWIG variables in Octave, a+b becomes a.__add(b). The wrapper is then free to implement __add to do whatever it wants. A wrapper may define the __add function manually, %rename some other function to it, or %rename a C++ operator to it.
By default the C++ operators are renamed to their corresponding Octave operators. So without doing any work, they just work.
For example, the following:
%inline {
struct A {
int value;
A(int _value) : value(_value) {}
A operator+ (const A& x) {
return A(value+x.value);
}
};
}
may be used naturally from Octave:
a=A(2), b=A(3), c=a+b assert(c.value==5);
Octave operators are mapped in the following way:
__brace a{args}
__brace_asgn a{args} = rhs
__paren a(args)
__paren_asgn a(args) = rhs
__str generates string rep
__not !a
__uplus +a
__uminus -a
__transpose a.'
__hermitian a'
__incr a++
__decr a--
__add a + b
__sub a - b
__mul a * b
__div a / b
__pow a ^ b
__ldiv a \ b
__lshift a << b
__rshift a >> b
__lt a < b
__le a <= b
__eq a == b
__ge a >= b
__gt a > b
__ne a != b
__el_mul a .* b
__el_div a ./ b
__el_pow a .^ b
__el_ldiv a .\ b
__el_and a & b
__el_or a | b
On the C++ side, the default mappings are as follows:
%rename(__add) *::operator+; %rename(__add) *::operator+(); %rename(__add) *::operator+() const; %rename(__sub) *::operator-; %rename(__uminus) *::operator-(); %rename(__uminus) *::operator-() const; %rename(__mul) *::operator*; %rename(__div) *::operator/; %rename(__mod) *::operator%; %rename(__lshift) *::operator<<; %rename(__rshift) *::operator>>; %rename(__el_and) *::operator&&; %rename(__el_or) *::operator||; %rename(__xor) *::operator^; %rename(__invert) *::operator~; %rename(__lt) *::operator<; %rename(__le) *::operator<=; %rename(__gt) *::operator>; %rename(__ge) *::operator>=; %rename(__eq) *::operator==; %rename(__ne) *::operator!=; %rename(__not) *::operator!; %rename(__incr) *::operator++; %rename(__decr) *::operator--; %rename(__paren) *::operator(); %rename(__brace) *::operator[];
The %extend directive works the same as in other modules.
You can use it to define special behavior, like for example defining Octave operators not mapped to C++ operators, or defining certain Octave mechanisms such as how an object prints. For example, the octave_value::{is_string,string_value,print} functions are routed to a special method __str that can be defined inside an %extend.
%extend A {
string __str() {
stringstream sout;
sout<<$self->value;
return sout.str();
}
}
Then in Octave one gets,
octave:1> a=A(4);
octave:2> a
a = 4
octave:3> printf("%s\n",a);
4
octave:4> a.__str()
4
C++ templates are fully supported, as in other modules.
C++ smart pointers are fully supported, as in other modules.
There is full support for SWIG Directors, which permits Octave code to subclass C++ classes, and implement their virtual methods.
Octave has no direct support for object oriented programming, however the swig_ref type provides some of this support. All SWIG types are wrapped inside a swig_ref. These handle calling set and get methods for C++ variables (see other SWIG docs), and invoking member functions (by prepending self parameter). You can aquire a swig_ref by having a wrapped function return a pointer, reference, or value of a non-primitive type. You can also manufacture one using the subclass function (provided by the SWIG/Octave runtime).
For example,
octave:1> a=subclass();
octave:2> a.my_var = 4;
octave:3> a.my_method = @(self) printf("my_var = ",self.my_var);
octave:4> a.my_method();
my_var = 4
subclass() can also be used to subclass one or more C++ types. Suppose you have an interface defined by
%inline {
class A {
public:
virtual my_method() {
printf("c-side routine called\n");
}
};
void call_your_method(A& a) {
a.my_method();
}
}
Then from Octave you can say:
octave:1> B=@() subclass(A(),@my_method);
octave:2> function my_method(self)
octave:3> printf("octave-side routine called\n");
octave:4> end
octave:5> call_your_method(B());
octave-side routine called
or more concisely,
octave:1> B=@() subclass(A(),'my_method',@(self) printf("octave-side routine called\n"));
octave:2> call_your_method(B());
octave-side routine called
Note that you have to enable directors via the %feature directive (see other modules for this).
subclass() will accept any number of C++ bases or other subclass()'ed objects, (string,octave_value) pairs, and function_handles. In the first case, these are taken as base classes; in the second case, as named members (either variables or functions, depending on whether the given value is a function handle); in the third case, as member functions whose name is taken from the given function handle. E.g.,
octave:1> B=@(some_var=2) subclass(A(),'some_var',some_var,@some_func,'another_func',@(self) do_stuff())
You can also assign non-C++ member variables and functions after construct time. There is no support for non-C++ static members.
There is limited support for explicitly referencing C++ bases. So, in the example above, we could have
octave:1> B=@() subclass(A(),@my_method);
octave:2> function my_method(self)
octave:3> self.A.my_method();
octave:4> printf("octave-side routine called\n");
octave:5> end
octave:6> call_your_method(B());
c-side routine called
octave-side routine called
The use of threads in wrapped Director code is not supported; i.e., an Octave-side implementation of a C++ class must be called from the Octave interpreter's thread. Anything fancier (apartment/queue model, whatever) is left to the user. Without anything fancier, this amounts to the limitation that Octave must drive the module... like, for example, an optimization package that calls Octave to evaluate an objective function.
All Octave objects are referenced counted internally. SWIG-wrapped objects are no different. This means that destructors get called when the Octave object's reference count goes to zero.
For example,
%inline {
class A {
public:
A() { printf("A constructing\n"); }
~A() { printf("A destructing\n"); }
};
}
Would produce this behavior in Octave:
octave:1> a=A(); A constructing octave:2> b=a; octave:3> clear a; octave:4> b=4; A destructing
In the case where one wishes for the C++ side to own an object that was created in Octave (especially a Director object), one can use the __disown() method to invert this logic. Then letting the Octave reference count go to zero will not destroy the object, but destroying the object will invalidate the Octave-side object if it still exists (and call destructors of other C++ bases in the case of multiple inheritance/subclass()'ing).
This is some skeleton support for various STL containers, but this work is not finished.
Octave provides a rich set of classes for dealing with matrices etc. Currently there are no typemaps to deal with those, though such support will be added soon. However, these are relatively straight forward for users to add themselves (see the docs on typemaps). Without much work (a single typemap decl-- say, 5 lines of code in the interface file), it would be possible to have a function
double my_det(const double* mat,int m,int n);
that is accessed from Octave as,
octave:1> my_det(rand(4)); ans = -0.18388