[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Extensions documentation
From: |
John W. Eaton |
Subject: |
Re: Extensions documentation |
Date: |
Tue, 21 Nov 2000 14:36:47 -0600 |
On 7-Nov-2000, Paul Kienzle <address@hidden> wrote:
| Now, to answer your questions.
|
| You let the octave interpreter know about your functions using
|
| DEFUN_DLD (name, args, nargout, "documentation string")
| {
| octave_value_list retval;
| int nargin = args.length();
|
| // function body
|
| return retval;
| }
|
| The actual arguments are of type octave_value, and can be accessed
| as args(0), args(1), ... args(nargin-1). In practice, you will want
| to manipulate the values as a specific type. First you must test
| that it is of the correct type, and then extract the value of that
| type. For example,
|
| if (args(0).is_real_scalar()) {
| double v = args(0).double_value();
|
| // action to take when processing double argument
| }
This is not always the best way since it doesn't handle any possible
automatic type conversions. You might want to use
double dval = args(0).double_value ();
if (! error_state)
{
// dval should be valid, so we can continue.
}
else
... ; // something went wrong, maybe we should print an error message ...
| All matrix elements can be accessed using subscripts as in x(i,j).
| An element can either be assigned to or returned from. You can force
| bounds checking by using x.checkelem(i,j) as your element reference.
| You can avoid bounds checking by using x.elem(i,j) as your element
| reference. Note that arrays in liboctave are copy-on-modify. If you
| assign one array to another, it simply copies a pointer to the data and
| increments a reference count. When you assign to an element of an array
| which is referenced from two places, it makes a copy of the entire array.
| x.xelem(i,j) does not check if it is a copy before operating. If you are
| passing the array to a FORTRAN or C subroutine, you can pass x.data()
| if the function will not modify the array, or x.fortran_vec() if you
| want to modify the array. fortran_vec() will make a unique copy of the
| array if it is referenced from more than one place. Note that the data
| is stored in FORTRAN rather than C array format. In C, treat it as a
| pointer to a vector, and reference the elements of the vector as rows*j+i.
This is essentially correct except that the bounds checking and
reference counting semantics are a bit more complicated. Here is a
summary:
check reference count check
(for non-const array
objects only) bounds
checkelem yes yes
elem yes no
xelem no no
operator() yes yes, if BOUNDS_CHECKING is
defined when compiling
Take a look at the declarations of xelem, checkelem, elem, and
operator() in liboctave/Array.h for the precise definitions.
This means that the const versions never worry about reference
counting because they return values and cannot accidentally let you
modify the contents of multiple arrays that share the same data. For
the non-const versions, copies are forced. So it can matter whether
you write
const Matrix x = ...;
or just
Matrix x = ...;
and then access elements. Generally, it is better to use const unless
you need to modify the object.
| The return values are easier since the octave_value constructor is
| overloaded to automatically convert the basic types into octave values.
| You simply assign retval(i) with the ith return value. You don't need
| to assign more than nargout values to retval since the interpreter will
| simply throw away the rest.
Also, the octave_value_list object will resize itself automatically,
so if you need to return N values from some function, you can don't
have to explicitly size the return value array. Just write
octave_value_list retval;
...
retval(N) = vN;
...
retval(2) = v2;
retval(1) = v1;
and the resize will only happen once (when vN is assigned). If you do
the assignments in the other order (v1, v2, ... vN) you will end up
resizing retval N times.
| In the Octave 2.1.x series, you can have multiple DEFUN_DLDs in the
| same .oct file. One of them must have the name of the oct file since
| that's how the interpreter finds the correct file to load.
No, it is not required. For example, Octave has minmax.cc which is
installed as minmax.oct. The installation also creates min.oct and
max.oct as hard links to that file though, so Octave can find the min
and max functions.
| However,
| once it is loaded, all DEFUN_DLD routines in the file are available.
No, Octave only loads one function at a time, but it does keep the
shared library in a list, and checks there first before looking on the
disk again. So, if Octave looks for min, it will find it by loading
min.oct (the same file as minmax.oct and max.oct, but Octave doesn't
know this) and putting min in the symbol table. Then Octave also
stores a pointer to the min.oct shared library in a list, for future
reference. If Octave needs to find max later, then it looks in the
list of shared libraries that are already loaded, and should find it
in the shared library object loaded from the file min.oct. You can
see this behavior if you do the following:
octave> min(rand (2));
octave> which min
min is the dynamically-linked function from the file
/usr/local/octave/2.1.31/libexec/octave/2.1.31/oct/i686-pc-linux-gnu/min.oct
octave> max (rand (2));
octave> which max
max is the dynamically-linked function from the file
/usr/local/octave/2.1.31/libexec/octave/2.1.31/oct/i686-pc-linux-gnu/min.oct
octave> clear min
octave> clear max
octave> max (rand (2));
octave:10> which max
max is the dynamically-linked function from the file
/usr/local/octave/2.1.31/libexec/octave/2.1.31/oct/i686-pc-linux-gnu/max.oct
octave:11> min (rand (2));
octave:12> which min
min is the dynamically-linked function from the file
/usr/local/octave/2.1.31/libexec/octave/2.1.31/oct/i686-pc-linux-gnu/max.oct
In the first case, Octave loaded min.oct and in the second, it loaded
max.oct (again, the same file, but Octave does not know that).
| The .oct file remains loaded until the DEFUN_DLD's are explicitly
| cleared. [true?]
That's what is supposed to happen. When you clear a function, Octave
removes it from the list of functions loaded from a given shared
library. Once the number of functions loaded from a shared library
falls to zero, the shared library is closed.
| In practice, this means that you name the octave
| file after your initialization procedure, and everything works fine.
| I usually find that the interpreter crashes if I recompile the .oct file
| out from under it, but I haven't tried it on recent versions of octave.
It is supposed to be possible to recompile .oct files and have them
reloaded automatically. At least it works for me on Linux systems.
If you have warn_reload_forces_clear = 1, you should see something
like this:
octave> foo
ans = foo
octave> which foo
foo is the dynamically-linked function from the file
/export/u0/jwe/foo.oct
octave> bar
ans = bar
octave:4> which bar
bar is the dynamically-linked function from the file
/export/u0/jwe/foo.oct
octave> <Control-Z>
[1]+ Stopped octave
$ mkoctfile foo.cc
$ ln -f foo.oct bar.oct
$ fg
octave
octave> foo
warning: reloading /export/u0/jwe/foo.oct clears the following functions:
warning: foo
warning: bar
ans = foo
octave> which bar
bar is the dynamically-linked function from the file
/export/u0/jwe/foo.oct
octave> which foo
foo is the dynamically-linked function from the file
/export/u0/jwe/foo.oct
octave> bar
ans = bar
For this example, I used the following functions, defined in the same
file.
#include <octave/oct.h>
DEFUN_DLD (foo, , ,
"")
{
return octave_value ("foo");
}
DEFUN_DLD (bar, , ,
"")
{
return octave_value ("bar");
}
jwe
-------------------------------------------------------------
Octave is freely available under the terms of the GNU GPL.
Octave's home on the web: http://www.octave.org
How to fund new projects: http://www.octave.org/funding.html
Subscription information: http://www.octave.org/archive.html
-------------------------------------------------------------