help-octave
[Top][All Lists]
Advanced

[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
-------------------------------------------------------------



reply via email to

[Prev in Thread] Current Thread [Next in Thread]