2

I want to use matrix algebra and optimization. I have tested different C and C++ libraries for matrix algebra but the problem with those is they cannot handle garbage data as good as GNU Octave does. Garbage data in C and C++ goes low to like e-8 but in GNU Octave it will be pushed down way to low as e-17. That's very useful if you planning to use garbage data from e.g measurement in calculations. They don't effect nothing of your results.

But GNU Octave have a C++ API, which I don't really understand how to use. But I want to use C and call GNU Octave functions from C.

Is that possible that I can create a struct that contains a 2D array and dimensions, and send it to GNU Octave and I will return a struct again that have the result and the dimension e.g solution.

euraad
  • 2,467
  • 5
  • 30
  • 51
  • 2
    "Garbage data"? Are you referring to the limits on IEEE754 floating-point arithmetic (single/double precision)? – Acorn May 16 '19 at 20:36
  • @Acorn No sorry. If you doing Singular Value Decomposition and you know the real size of the S-matrix, but the S-matrix is much larger than the real world size. Those values in GNU Octave is garbage data. – euraad May 16 '19 at 20:42
  • 2
    I couldn't find any information in google about the C API; just C++. I would suggest you to open the header files and inspect them. Or find any software that makes use of it (I don't know any). – alx - recommends codidact May 16 '19 at 21:01
  • 1
    Interesting case, I second Cacahuete Frito in that I see there is a C++ API, this [mirror](https://github.com/NexMirror/Octave) may be useful, as well as [this question](https://stackoverflow.com/questions/9246444/how-to-embed-the-gnu-octave-in-c-c-program#9246607). – Sigve Karolius May 16 '19 at 21:09
  • 3
    @Heretic I still don't know what you are referring to. I suspect you are talking about factorizing not-so-well-behaved matrices that result in very small numbers; and Octave behaving better for those than your C/C++ version. Still, if you want to use Octave's algorithm, and the API is in C++, you will have to create a wrapper to call them from C. – Acorn May 16 '19 at 21:34
  • 1
    use double instead of float. – Jasen May 17 '19 at 06:25
  • @Acorn The thing is that the octave documentation says there is a C API; but that API is not documented anywhere. So if he manages to get the library and header files somehow, maybe he can decipher them by trial and error. – alx - recommends codidact May 17 '19 at 07:18
  • @Jasen For performance? Use `double_t` instead of `double` :) – alx - recommends codidact May 17 '19 at 07:19
  • The C++ interface is quite nice, and if you can write in C, then there is very little you would need to learn to make use of the C++ needed. For example [C++ Examples with Octave](https://octave.org/doc/v4.0.1/Standalone-Programs.html#Standalone-Programs) – David C. Rankin May 18 '19 at 09:37

1 Answers1

5

There is a c mex interface. However the octave interpreter must be embedded and initialized before any mex function can be called. As of Octave 4.4 octave_main as suggested by the linked answer has been deprecated and some other changes also are needed for it to be useful for mex programs. So I have prepared a c++ source file calloctave.cc containing the functions mexCallOctave and free_arg_list and its header calloctave.h.

calloctave.cc

// calloctave.cc

#include "interpreter.h"
#include "mxarray.h"
#include "parse.h"

extern "C"
int
mexCallOctave (int nargout, mxArray *argout[], int nargin,
               mxArray *argin[], const char *fname)
{

  static octave::interpreter embedded_interpreter;
  if (!embedded_interpreter.initialized())
    embedded_interpreter.execute ();

  octave_value_list args;

  args.resize (nargin);

  for (int i = 0; i < nargin; i++)
    args(i) = mxArray::as_octave_value (argin[i]);

  bool execution_error = false;

  octave_value_list retval;


  retval = octave::feval (fname, args, nargout);

  int num_to_copy = retval.length ();

  if (nargout < retval.length ())
    num_to_copy = nargout;

  for (int i = 0; i < num_to_copy; i++)
    {
      argout[i] = new mxArray (retval(i));
    }

  while (num_to_copy < nargout)
    argout[num_to_copy++] = nullptr;

  return execution_error ? 1 : 0;
}

extern "C"
void 
free_arg_list (int nargs, mxArray* arglist[])
{
    for(int i = 0; i < nargs; i++)
            delete arglist[i];
}

calloctave.h

// calloctave.h
#pragma once
#include "mex.h"

#if defined  (__cplusplus)
extern "C" {
#endif

int
mexCallOctave (int nargout, mxArray *argout[], int nargin,
               mxArray *argin[], const char *fname);
void 
free_arg_list (int nargs, mxArray* arglist[]);

#if defined  (__cplusplus)
}
#endif

Here is a basic introduction into mex files. You can compile an example hello world program adding the option --verbose as mkoctfile --mex --verbose hello.c to get the list of compiler options that you need to use them for compilation of your actual programs. Note that because calloctave.cc is a c++ source it should be compiled using a c++ compiler such as g++. In the following example a m function "myfunction" is called. It gets one input and produces one output. mexCallOctave is used for calling the octave function and it has the same signature as mexCallMATLAB.

myfunction.m

% myfunction.m
function out=  myfunction( a )
    out = sum(a);
endfunction

main.c

//main.c
#include <stdio.h>
#include "calloctave.h"   
int main()
{
    double input_data[] = {0,1,2,3,4,5,6,7,8,9,10};

    const int nargin = 1;
    const int nargout = 1;
    mxArray* rhs[nargin];
    mxArray* lhs[nargout];

    // allocate mex array
    rhs[0] = mxCreateDoubleMatrix( 10, 1, mxREAL);
    double* rhs_ptr = mxGetPr( rhs[0] );

    // copy data from input buffer to mex array
    for (int i = 0 ; i < 10; i++)
        rhs_ptr[i] = input_data[i];

    // call octave function
    mexCallOctave(nargout, lhs, nargin, rhs, "myfunction");

    double* lhs_ptr = mxGetPr( lhs[0] );

    double output_data = *lhs_ptr;

    // show the result
    printf ("result = %f", output_data);

    // free memory

    mxDestroyArray(rhs[0]);
    free_arg_list(nargout, lhs);
}
rahnema1
  • 15,264
  • 3
  • 15
  • 27
  • 1
    A nearly perfect answer. For me (a rank beginner), it took a while to realize that these two .cc files have to be compiled with the mkoctfile script (installed by octave) like "mkoctfile --link-stand-alone calloctave.cc main.cc -o main". BTW, the answer is not 45 but 55, the famous 'off by one' error. I suspect you did that on purpose to punish us C folks :--) – Marcel Hendrix May 14 '21 at 15:58
  • @MarcelHendrix Good catch! Actually here you don't need mkoctfile to compile the program. You can use it with - - verbose option to get the compiler options. [Here](https://stackoverflow.com/questions/64569560/calling-octave-interpreter-from-c-problems-compiling-and-running-example?noredirect=1&lq=1#comment114177519_64569560) l have recommended to use some compiler options related to this qustion. – rahnema1 May 14 '21 at 19:23
  • This comment has been very helpful. I almost have it compiled but am falling at the last hurdle. I've found the octave include path and have compiled all the object files, but I'm not how to compile the binary and link to the relevant octave libraries – DJames Jan 14 '22 at 09:46
  • Prepare an empty .cpp file like `a.cpp` and open octave and type `mkoctfile -n a.cpp` . Two commands are listed, one for compilation and other for linking. Use those printed options for your compilation work. Use gcc for linking. In the options don't use `-shared`. Place `-lstdc++` at the end of linking options for gcc. – rahnema1 Jan 14 '22 at 12:08