octave-maintainers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Documentation for Manual for Dynamically Linked Functions


From: David Bateman
Subject: Re: Documentation for Manual for Dynamically Linked Functions
Date: Wed, 25 Apr 2007 23:54:36 +0200
User-agent: Thunderbird 1.5.0.7 (X11/20060921)

David Bateman wrote:
> John W. Eaton wrote:
>> I also added a copyright stament to the top of dynamic.txi.  If some
>> of the text is based on other sources, please add the names of the
>> other authors here.
> 
> Ok, I have a largish patch to dynamic.txi to send and will include it in
> that..

Ok, here is my latest bit of documentation for dynamic.txi, It

* Add copyrights for Paul Thomas and Christophe Spiel to credit the Coda
and Dal Segno source material.
* It adds a section on oct-file input parameter checking
* It adds a section of documentation and test/assert in oct-files
* It expands the basic section on mex-files and adds some other sections
(empty or only with the relevant source for the examples directory).
* Writes a section on calling other functions from mex-files
* A few formatting issues in a couple of example files
* Adds example files paramdemo.cc and myfunc.c

A ChangeLog entry is also attached. The section on dynamically linked
functions is still not complete, but its getting to be relatively
substantial.

Regards
David



*** ./doc/interpreter/dynamic.txi.orig14        2007-04-25 18:04:59.000000000 
+0200
--- ./doc/interpreter/dynamic.txi       2007-04-25 20:58:28.096374073 +0200
***************
*** 1,4 ****
--- 1,5 ----
  @c Copyright (C) 2007 John W. Eaton, David Bateman
+ @c Copyright (C) 2007 Paul Thomas, Christoph Spiel
  @c This is part of the Octave manual.
  @c For copying conditions, see the file gpl.texi.
  
***************
*** 974,980 ****
  @node Input Parameter Checking in Oct-Files
  @subsection Input Parameter Checking in Oct-Files
  
! WRITE ME
  
  @node Exception and Error Handling in Oct-Files
  @subsection Exception and Error Handling in Oct-Files
--- 975,1013 ----
  @node Input Parameter Checking in Oct-Files
  @subsection Input Parameter Checking in Oct-Files
  
! As oct-files are compiled functions they have the possibility of causing
! Octave to abort abnormally.  It is therefore inportant that the input
! parameters to each and every function has the minimum of parameter
! checking needed to ensure that Octave behaves well.
! 
! The minimum requirement, as previously discussed, is to check the number
! of input arguments before using them to avoid referencing a non existent
! argument.  However, it some case this might not be sufficient as the
! underlying code imposes further constraints. For example an external
! function call might be undefined if the input arguments are not
! integers, or if one of the arguments is zero. Therefore, oct-files often
! need additional input parameter checking.
! 
! There are several functions within Octave that might be useful for the
! purposes of parameter checking. These include the methods of the
! octave_value class like @code{is_real_matrix}, etc, but equally include
! more specialized functions. Some of the more common ones are
! demonstrated in the following example
! 
! @examplefile{paramdemo.cc}
! 
! @noindent
! and an example of its use is
! 
! @example
! @group
! paramdemo ([1, 2, NaN, Inf])
! @result{} Properties of input array:
!       includes Inf or NaN values
!       includes other values than 1 and 0
!       includes only int, Inf or NaN values
! @end group
! @end example
  
  @node Exception and Error Handling in Oct-Files
  @subsection Exception and Error Handling in Oct-Files
***************
*** 1050,1056 ****
  @node Documentation and Test of Oct-Files
  @subsection Documentation and Test of Oct-Files
  
! WRITE ME, reference how to use Texinfo in oct-file and embed test code.
  
  @node Application Programming Interface for Oct-Files
  @subsection Application Programming Interface for Oct-Files
--- 1083,1143 ----
  @node Documentation and Test of Oct-Files
  @subsection Documentation and Test of Oct-Files
  
! The documentation of an oct-file is the fourth string parameter of the
! @code{DEFUN_DLD} macro.  This string can be formatted in the same manner
! as the help strings for user functions (@ref{Documentation Tips}),
! however there are some issue that are particular to the formatting of
! help strings within oct-files.
! 
! The major issue is that the help string will typically be longer than a
! single line of text, and so the formatting of long help strings need to
! be taken into account. There are several manner in which to happen this
! issue, but the most common is illustrated in the following example
! 
! @example
! @group
! DEFUN_DLD (do_what_i_want, args, nargout, 
!   "-*- texinfo -*-\n\
! @@deftypefn @{Function address@hidden @address@hidden do_what_i_say 
(@@address@hidden@})\n\
! A function that does what the user actually wants rather than what\n\
! they requested.\n\
! @@end deftypefn")
! @{
! @dots{}
! @}
! @end group
! @end example
! 
! @noindent
! where, as can be seen, end line of text within the help string is
! terminated by @code{\n\} which is an an embedded new-line in the string
! together with a C++ string continuation character.  Note that the final
! @code{\} must be the last character on the line.
! 
! Octave also includes the ability to embed the test and demonstration
! code for a function within the code itself (@ref{Test and Demo Functions}).
! This can be used from within oct-files (or in fact any file) with
! certain provisos.  Firstly, the test and demo functions of Octave look
! for a @code{%!} as the first characters on a new-line to identify test
! and demonstration code.  This is equally a requirement for
! oct-files.  Furthermore the test and demonstration code must be included
! in a comment block of the compiled code to avoid it being interpreted by
! the compiler.  Finally, he Octave test and demonstration code must have
! access to the source code of the oct-file and not just the compiled code
! as th<e tests are stripped from the compiled code. An example in an
! oct-file might be
! 
! @example
! @group
! /*
! 
! %!error (sin())
! %!error (sin(1,1))
! %!assert (sin([1,2]),[sin(1),sin(2)])
! 
! */
! @end group
! @end example
  
  @node Application Programming Interface for Oct-Files
  @subsection Application Programming Interface for Oct-Files
***************
*** 1076,1084 ****
  
  @menu
  * Getting Started with Mex-Files::  
  * Structures with Mex-Files::  
  * Sparse Matrices with Mex-Files::  
! * Calling External Functions in Mex-Files::  
  @end menu
  
  @node Getting Started with Mex-Files
--- 1163,1175 ----
  
  @menu
  * Getting Started with Mex-Files::  
+ * Working with Matrices and Arrays in Mex-Files::  
+ * Character Strings in Mex-Files::  
+ * Cell Arrays with Mex-Files::  
  * Structures with Mex-Files::  
  * Sparse Matrices with Mex-Files::  
! * Calling Other Functions in Mex-Files::  
! * Application Programming Interface for Mex-Files::  
  @end menu
  
  @node Getting Started with Mex-Files
***************
*** 1103,1127 ****
  
  @examplefile{firstmexdemo.c}
  
! This simple example demonstrates the basics of writing a mex-file.
  
  WRITE ME
  
  @node Structures with Mex-Files
  @subsection Structures with Mex-Files
  
  WRITE ME
  
  @node Sparse Matrices with Mex-Files
  @subsection Sparse Matrices with Mex-Files
  
! WRITE ME
  
! @node Calling External Functions in Mex-Files
! @subsection Calling External Functions in Mex-Files
  
  WRITE ME
  
  @node Standalone Programs
  @section Standalone Programs
  
--- 1194,1340 ----
  
  @examplefile{firstmexdemo.c}
  
! This simple example demonstrates the basics of writing a mex-file. The
! entry point into the mex-file is defined by @code{mexFunction}. Note
! that the function name is not explicitly included in the
! @code{mexFunction} and so there can only be a single @code{mexFunction}
! entry point per-file.  Also the name of the function is determined by the
! name of the mex-file itself.  Therefore if the above function is in the
! file @file{firstmexdemo.c}, it can be compiled with
! 
! @example
! mkoctfile --mex firstmexdemo.c
! @end example
! 
! @noindent
! which creates a file @file{firstmexdemo.mex}.  The function can then be run
! from Octave as
! 
! @example
! @group
! firstmexdemo()
! @result{} 1.2346
! @end group
! @end example
! 
! It should be noted that the mex-file contains no help string for the
! functions it contains. To document mex-files, there should exist an
! m-file in the same directory as the mex-file itself. Taking the above as
! an example, we would therefore have a file @file{firstmexdemo.m} that might
! contain the text
! 
! @example
! %FIRSTMEXDEMO Simple test of the functionality of a mex-file.
! @end example
! 
! In this case, the function that will be executed within Octave will be
! given by the mex-file, while the help string will come from the
! m-file. This can also be useful to allow a sample implementation of the
! mex-file within the Octave language itself for testing purposes.
! 
! Although we can not have multiple entry points into a single mex-file,
! we can use the @code{mexFunctionName} function to determine what name
! the mex-file was called with. This can be used to alter the behavior of
! the mex-file based on the function name. For example if
! 
! @examplefile{myfunc.c}
! 
! @noindent
! is in file @file{myfunc.c}, and it is compiled with
! 
! @example
! @group
! mkoctfile --mex myfunc.c
! ln -s myfunc.mex myfunc2.mex
! @end group
! @end example
! 
! Then as can be seen by
! 
! @example
! @group
! myfunc()
! @result{} You called function: myfunc
!     This is the principal function
! myfunc2()
! @result{} You called function: myfunc2
! @end group
! @end example
! 
! @noindent
! the behavior of the mex-file can be altered depending on the functions
! name.
! 
! @node Working with Matrices and Arrays in Mex-Files
! @subsection Working with Matrices and Arrays in Mex-Files
! 
! The basic mex type of all variables is @code{mxArray}. All variables,
! such as Matrices, cell arrays or structures are all stored in this basic
! type, and this type serves basically the same purpose as the
! octave_value class in oct-files. That is it acts as a container for the
! more specialized types.
! 
! WRITE ME
! 
! @node Character Strings in Mex-Files
! @subsection Character Strings in Mex-Files
! 
! WRITE ME
! 
! @node Cell Arrays with Mex-Files
! @subsection Cell Arrays with Mex-Files
  
  WRITE ME
  
  @node Structures with Mex-Files
  @subsection Structures with Mex-Files
  
+ See the file @file{mystruct.c}
+ 
+ @examplefile{mystruct.c}
+ 
  WRITE ME
  
  @node Sparse Matrices with Mex-Files
  @subsection Sparse Matrices with Mex-Files
  
! See the file @file{mysparse.c}
  
! @examplefile{mysparse.c}
  
  WRITE ME
  
+ @node Calling Other Functions in Mex-Files
+ @subsection Calling Other Functions in Mex-Files
+ 
+ It is also possible call other Octave functions from within a mex-file
+ using @code{mexCallMATLAB}. An example of the use of
+ @code{mexCallMATLAB} can be see in the example below
+ 
+ @examplefile{myfeval.c}
+ 
+ If this code is in the file @file{myfeval.c}, and is compiled to
+ @file{myfeval.mex}, then an example of its use is
+ 
+ @example
+ @group
+ myfeval("sin", 1)
+ a = myfeval("sin", 1)
+ @result{} Hello, World!
+     I have 2 inputs and 1 outputs
+     I'm going to call the interpreter function sin
+     a =  0.84147
+ @end group
+ @end example
+ 
+ Note that it is not possible to use function handles or inline functions
+ within a mex-file.
+ 
+ @node Application Programming Interface for Mex-Files
+ @subsection Application Programming Interface for Mex-Files
+ 
+ WRITE ME, refer to mex.h and mexproto.h
+ 
  @node Standalone Programs
  @section Standalone Programs
  
***************
*** 1154,1159 ****
--- 1367,1373 ----
  @end group
  @end example
  
+ @noindent
  mkoctfile can then be used to build a standalone application with a
  command like
  
*** ./examples/myfunc.c.orig14  2007-04-25 14:20:46.227535609 +0200
--- ./examples/myfunc.c 2007-04-25 13:46:20.062621169 +0200
***************
*** 0 ****
--- 1,12 ----
+ #include "mex.h"
+ 
+ void
+ mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
+ {
+   const char *nm;
+   nm = mexFunctionName ();
+   mexPrintf("You called function: %s\n", nm);
+   if (strcmp (nm, "myfunc") == 0)
+     mexPrintf("This is the principal function\n", nm);
+   return; 
+ }
*** ./examples/mystruct.c.orig14        2007-04-25 14:21:11.812297992 +0200
--- ./examples/mystruct.c       2007-04-25 20:56:31.095418845 +0200
***************
*** 13,21 ****
    for (i = 0; i < mxGetNumberOfFields (prhs[0]); i++)
      for (j=0; j < mxGetNumberOfElements(prhs[0]); j++)
        {
!       mexPrintf ("field %s(%d) = ", mxGetFieldNameByNumber (prhs[0], i), j);
!       v = mxGetFieldByNumber (prhs[0], j, i);
!       mexCallMATLAB(0, 0, 1, &v, "disp");
        }
  
    v = mxCreateStructMatrix (2, 2, 2, keys);
--- 13,22 ----
    for (i = 0; i < mxGetNumberOfFields (prhs[0]); i++)
      for (j=0; j < mxGetNumberOfElements(prhs[0]); j++)
        {
!         mexPrintf ("field %s(%d) = ", 
!                    mxGetFieldNameByNumber (prhs[0], i), j);
!         v = mxGetFieldByNumber (prhs[0], j, i);
!         mexCallMATLAB(0, 0, 1, &v, "disp");
        }
  
    v = mxCreateStructMatrix (2, 2, 2, keys);
*** ./examples/mysparse.c.orig14        2007-04-25 14:22:50.826487478 +0200
--- ./examples/mysparse.c       2007-04-25 20:57:09.901413960 +0200
***************
*** 20,27 ****
    
    if (mxIsComplex (prhs[0]))
      {
!       mexPrintf ("Matrix is %d-by-%d complex sparse matrix with %d 
elements\n",
!               m, n, nz);
  
        pr = mxGetPr (prhs[0]);
        pi = mxGetPi (prhs[0]);
--- 20,27 ----
    
    if (mxIsComplex (prhs[0]))
      {
!       mexPrintf ("Matrix is %d-by-%d complex sparse matrix", m, n);
!       mexPrintf (" with %d elements\n", nz);
  
        pr = mxGetPr (prhs[0]);
        pi = mxGetPi (prhs[0]);
***************
*** 30,37 ****
  
        i = n;
        while (jc[i] == jc[i-1] && i != 0) i--;
!       mexPrintf ("last non-zero element (%d, %d) = (%g, %g)\n", ir[nz-1]+ 1, 
!               i, pr[nz-1], pi[nz-1]);
  
        v = mxCreateSparse (m, n, nz, mxCOMPLEX);
        pr2 = mxGetPr (v);
--- 30,37 ----
  
        i = n;
        while (jc[i] == jc[i-1] && i != 0) i--;
!       mexPrintf ("last non-zero element (%d, %d) = (%g, %g)\n", 
!                 ir[nz-1]+ 1, i, pr[nz-1], pi[nz-1]);
  
        v = mxCreateSparse (m, n, nz, mxCOMPLEX);
        pr2 = mxGetPr (v);
***************
*** 40,61 ****
        jc2 = mxGetJc (v);
        
        for (i = 0; i < nz; i++)
!       {
!         pr2[i] = 2 * pr[i];
!         pi2[i] = 2 * pi[i];
!         ir2[i] = ir[i];
!       }
        for (i = 0; i < n + 1; i++)
!       jc2[i] = jc[i];
  
        if (nlhs > 0)
!       plhs[0] = v;
      }
    else if (mxIsLogical (prhs[0]))
      {
        bool *pbr, *pbr2;
!       mexPrintf ("Matrix is %d-by-%d logical sparse matrix with %d 
elements\n",
!               m, n, nz);
  
        pbr = mxGetLogicals (prhs[0]);
        ir = mxGetIr (prhs[0]);
--- 40,61 ----
        jc2 = mxGetJc (v);
        
        for (i = 0; i < nz; i++)
!         {
!           pr2[i] = 2 * pr[i];
!           pi2[i] = 2 * pi[i];
!           ir2[i] = ir[i];
!         }
        for (i = 0; i < n + 1; i++)
!         jc2[i] = jc[i];
  
        if (nlhs > 0)
!         plhs[0] = v;
      }
    else if (mxIsLogical (prhs[0]))
      {
        bool *pbr, *pbr2;
!       mexPrintf ("Matrix is %d-by-%d logical sparse matrix", m, n);
!       mexPrintf (" with %d elements\n", nz);
  
        pbr = mxGetLogicals (prhs[0]);
        ir = mxGetIr (prhs[0]);
***************
*** 64,70 ****
        i = n;
        while (jc[i] == jc[i-1] && i != 0) i--;
        mexPrintf ("last non-zero element (%d, %d) = %d\n", ir[nz-1]+ 1, 
!               i, pbr[nz-1]);
  
        v = mxCreateSparseLogicalMatrix (m, n, nz);
        pbr2 = mxGetLogicals (v);
--- 64,70 ----
        i = n;
        while (jc[i] == jc[i-1] && i != 0) i--;
        mexPrintf ("last non-zero element (%d, %d) = %d\n", ir[nz-1]+ 1, 
!                 i, pbr[nz-1]);
  
        v = mxCreateSparseLogicalMatrix (m, n, nz);
        pbr2 = mxGetLogicals (v);
***************
*** 72,92 ****
        jc2 = mxGetJc (v);
        
        for (i = 0; i < nz; i++)
!       {
!         pbr2[i] = pbr[i];
!         ir2[i] = ir[i];
!       }
        for (i = 0; i < n + 1; i++)
!       jc2[i] = jc[i];
  
        if (nlhs > 0)
!       plhs[0] = v;
      }
    else
      {
!       
!       mexPrintf ("Matrix is %d-by-%d real sparse matrix with %d elements\n",
!               m, n, nz);
  
        pr = mxGetPr (prhs[0]);
        ir = mxGetIr (prhs[0]);
--- 72,91 ----
        jc2 = mxGetJc (v);
        
        for (i = 0; i < nz; i++)
!         {
!           pbr2[i] = pbr[i];
!           ir2[i] = ir[i];
!         }
        for (i = 0; i < n + 1; i++)
!         jc2[i] = jc[i];
  
        if (nlhs > 0)
!         plhs[0] = v;
      }
    else
      {
!       mexPrintf ("Matrix is %d-by-%d real sparse matrix", m, n);
!       mexPrintf (" with %d elements\n", nz);
  
        pr = mxGetPr (prhs[0]);
        ir = mxGetIr (prhs[0]);
***************
*** 95,101 ****
        i = n;
        while (jc[i] == jc[i-1] && i != 0) i--;
        mexPrintf ("last non-zero element (%d, %d) = %g\n", ir[nz-1]+ 1, 
!               i, pr[nz-1]);
  
        v = mxCreateSparse (m, n, nz, mxREAL);
        pr2 = mxGetPr (v);
--- 94,100 ----
        i = n;
        while (jc[i] == jc[i-1] && i != 0) i--;
        mexPrintf ("last non-zero element (%d, %d) = %g\n", ir[nz-1]+ 1, 
!                 i, pr[nz-1]);
  
        v = mxCreateSparse (m, n, nz, mxREAL);
        pr2 = mxGetPr (v);
***************
*** 103,116 ****
        jc2 = mxGetJc (v);
        
        for (i = 0; i < nz; i++)
!       {
!         pr2[i] = 2 * pr[i];
!         ir2[i] = ir[i];
!       }
        for (i = 0; i < n + 1; i++)
!       jc2[i] = jc[i];
  
        if (nlhs > 0)
!       plhs[0] = v;
      }
  }
--- 102,115 ----
        jc2 = mxGetJc (v);
        
        for (i = 0; i < nz; i++)
!         {
!           pr2[i] = 2 * pr[i];
!           ir2[i] = ir[i];
!         }
        for (i = 0; i < n + 1; i++)
!         jc2[i] = jc[i];
  
        if (nlhs > 0)
!         plhs[0] = v;
      }
  }
*** ./examples/fortdemo.cc.orig14       2007-04-25 14:27:53.050625020 +0200
--- ./examples/fortdemo.cc      2007-04-25 20:51:19.895496768 +0200
***************
*** 24,30 ****
            octave_idx_type na = a.nelem ();
            OCTAVE_LOCAL_BUFFER (char, ctmp, 128);
  
!           F77_XFCN (fortsub, FORTSUB, (na, av, ctmp F77_CHAR_ARG_LEN (128)));
  
            if (f77_exception_encountered)
              error ("fortdemo: error in fortran");
--- 24,31 ----
            octave_idx_type na = a.nelem ();
            OCTAVE_LOCAL_BUFFER (char, ctmp, 128);
  
!           F77_XFCN (fortsub, FORTSUB, (na, av, ctmp 
!                                        F77_CHAR_ARG_LEN (128)));
  
            if (f77_exception_encountered)
              error ("fortdemo: error in fortran");
*** ./examples/paramdemo.cc.orig14      2007-04-25 16:57:17.787027733 +0200
--- ./examples/paramdemo.cc     2007-04-25 20:51:02.777381163 +0200
***************
*** 0 ****
--- 1,30 ----
+ #include <octave/oct.h>
+ 
+ DEFUN_DLD (paramdemo, args, nargout, "Parameter Check Demo.")
+ {
+   int nargin = args.length ();
+   octave_value retval;
+ 
+   if (nargin != 1)
+     print_usage();
+   else if (nargout != 0)
+     error ("paramdemo: function has no output arguments");
+   else
+     {
+       NDArray m = args(0).array_value();
+       double min_val = -10.0;
+       double max_val = 10.0;
+       octave_stdout << "Properties of input array:\n";
+       if (m.any_element_is_negative ())
+         octave_stdout << "  includes negative values\n";
+       if (m.any_element_is_inf_or_nan())
+         octave_stdout << "  includes Inf or NaN values\n";
+       if (m.any_element_not_one_or_zero())
+         octave_stdout << "  includes other values than 1 and 0\n";
+       if (m.all_elements_are_int_or_inf_or_nan())
+         octave_stdout << "  includes only int, Inf or NaN values\n";
+       if (m.all_integers (min_val, max_val))
+         octave_stdout << "  includes only integers in [-10,10]\n";
+     }
+   return retval;
+ }
2007-04-25  David Bateman  <address@hidden>

        * interpreter/dynamic.txi: Add additional copyrights. Add sections
        of input parameter checking, documentation and testing of
        oct-files. Adds a section on calling other functions from
        mex-files, expands the basic information on mex-files, and add a
        few new sections (to be completed) to the section about mex-files

2007-04-25  David Bateman  <address@hidden>

        * examples/myfunc.c, exampples/paramdemo.cc: New files
        * examples/mystruct.c, examples/mysparse.c, fortdemo.cc: Fix a few
        formatting issues when included in texinfo files.

reply via email to

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