0

I have a neural network trained in Matlab. Now, I want to use this network in Fortran. So, I followed the instructions given here: https://www.mathworks.com/help/deeplearning/ref/network.genfunction.html:

%% First, train a static network and calculate its outputs for the training data.
[x,t] = bodyfat_dataset;
bodyfatNet = feedforwardnet(10);
bodyfatNet = train(bodyfatNet,x,t);
y = bodyfatNet(x);
%% Next, generate and test a MATLAB function. Then the new function is compiled to a shared/dynamically linked library with mcc.
genFunction(bodyfatNet,'bodyfatFcn');
y2 = bodyfatFcn(x);
accuracy2 = max(abs(y-y2))
mcc -W lib:libBodyfat -T link:lib bodyfatFcn

This leads to the generation of files with extensions .c, .h and .so

In the Fortran code test.F90, I want to be able to compute y_test for a given x_test: y_test = bodyfatNet(x_test); Could you please tell me how this can be done/written?

Here below is my Makefile. I can make an executable from object file test.o and the shared object .so:

FORTRAN_COMPILER=gfortran
#FORTRAN_FLAGS=-O3 -Wall -Wextra -std=f2008 
FORTRAN_FLAGS=-ffree-line-length-none

OBJ2 = libBodyfat.so

SRC1= test.F90
OBJ1 = $(SRC1:.F90=.o)

LIBS     =  $(OBJ1) $(OBJ2)

%.o: %.F90
    @echo 'converting .F90 files to .o'
    $(FORTRAN_COMPILER) $(FORTRAN_FLAGS) -o $@ -c $<

binary: $(LIBS)
    @echo 'make an executable from objet files (.o) and the shared object (.so)'
    $(FORTRAN_COMPILER) $(FORTRAN_FLAGS) -o $@ $(LIBS)
clean:  
    @echo 'cleaning'
    @rm -f *.mod *.o binary

I am not certain if utilizing only ‘.so’ would suffice. But the more general question is how from test.F90 I can use the network.

UPDATE: As suggested by PierU, the problem is more of "how to call C routines from Fortran?". Below, you find the content of the generated .h file and .c file:

/*
 * MATLAB Compiler: 8.2 (R2021a)
 * Date: Wed Feb  8 15:21:13 2023
 * Arguments: "-B""macro_default""-W""lib:libBodyfat""-T""link:lib""bodyfatFcn"
 */

#ifndef libBodyfat_h
#define libBodyfat_h 1

#if defined(__cplusplus) && !defined(mclmcrrt_h) && defined(__linux__)
#  pragma implementation "mclmcrrt.h"
#endif
#include "mclmcrrt.h"
#ifdef __cplusplus
extern "C" { // sbcheck:ok:extern_c
#endif

/* This symbol is defined in shared libraries. Define it here
 * (to nothing) in case this isn't a shared library. 
 */
#ifndef LIB_libBodyfat_C_API 
#define LIB_libBodyfat_C_API /* No special import/export declaration */
#endif

/* GENERAL LIBRARY FUNCTIONS -- START */

extern LIB_libBodyfat_C_API 
bool MW_CALL_CONV libBodyfatInitializeWithHandlers(
       mclOutputHandlerFcn error_handler, 
       mclOutputHandlerFcn print_handler);

extern LIB_libBodyfat_C_API 
bool MW_CALL_CONV libBodyfatInitialize(void);

extern LIB_libBodyfat_C_API 
void MW_CALL_CONV libBodyfatTerminate(void);

extern LIB_libBodyfat_C_API 
void MW_CALL_CONV libBodyfatPrintStackTrace(void);

/* GENERAL LIBRARY FUNCTIONS -- END */

/* C INTERFACE -- MLX WRAPPERS FOR USER-DEFINED MATLAB FUNCTIONS -- START */

extern LIB_libBodyfat_C_API 
bool MW_CALL_CONV mlxBodyfatFcn(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[]);

/* C INTERFACE -- MLX WRAPPERS FOR USER-DEFINED MATLAB FUNCTIONS -- END */

/* C INTERFACE -- MLF WRAPPERS FOR USER-DEFINED MATLAB FUNCTIONS -- START */

extern LIB_libBodyfat_C_API bool MW_CALL_CONV mlfBodyfatFcn(int nargout, mxArray** Y, mxArray** Xf, mxArray** Af, mxArray* X, mxArray* _U4b, mxArray* _U4c);

#ifdef __cplusplus
}
#endif
/* C INTERFACE -- MLF WRAPPERS FOR USER-DEFINED MATLAB FUNCTIONS -- END */

#endif

This is the content of .c file:

    /*
 * MATLAB Compiler: 8.2 (R2021a)
 * Date: Wed Feb  8 15:21:13 2023
 * Arguments: "-B""macro_default""-W""lib:libBodyfat""-T""link:lib""bodyfatFcn"
 */

#define EXPORTING_libBodyfat 1
#include "libBodyfat.h"

static HMCRINSTANCE _mcr_inst = NULL; /* don't use nullptr; this may be either C or C++ */

#ifdef __cplusplus
extern "C" { // sbcheck:ok:extern_c
#endif

static int mclDefaultPrintHandler(const char *s)
{
    return mclWrite(1 /* stdout */, s, sizeof(char)*strlen(s));
}

#ifdef __cplusplus
} /* End extern C block */
#endif

#ifdef __cplusplus
extern "C" { // sbcheck:ok:extern_c
#endif

static int mclDefaultErrorHandler(const char *s)
{
    int written = 0;
    size_t len = 0;
    len = strlen(s);
    written = mclWrite(2 /* stderr */, s, sizeof(char)*len);
    if (len > 0 && s[ len-1 ] != '\n')
        written += mclWrite(2 /* stderr */, "\n", sizeof(char));
    return written;
}

#ifdef __cplusplus
} /* End extern C block */
#endif

/* This symbol is defined in shared libraries. Define it here
 * (to nothing) in case this isn't a shared library. 
 */
#ifndef LIB_libBodyfat_C_API
#define LIB_libBodyfat_C_API /* No special import/export declaration */
#endif

LIB_libBodyfat_C_API 
bool MW_CALL_CONV libBodyfatInitializeWithHandlers(
    mclOutputHandlerFcn error_handler,
    mclOutputHandlerFcn print_handler)
{
    int bResult = 0;
    if (_mcr_inst)
        return true;
    if (!mclmcrInitialize())
        return false;
    {
        mclCtfStream ctfStream = 
            mclGetEmbeddedCtfStream((void *)(libBodyfatInitializeWithHandlers));
        if (ctfStream) {
            bResult = mclInitializeComponentInstanceEmbedded(&_mcr_inst,
                                                             error_handler, 
                                                             print_handler,
                                                             ctfStream);
            mclDestroyStream(ctfStream);
        } else {
            bResult = 0;
        }
    }  
    if (!bResult)
    return false;
    return true;
}

LIB_libBodyfat_C_API 
bool MW_CALL_CONV libBodyfatInitialize(void)
{
    return libBodyfatInitializeWithHandlers(mclDefaultErrorHandler, 
                                          mclDefaultPrintHandler);
}

LIB_libBodyfat_C_API 
void MW_CALL_CONV libBodyfatTerminate(void)
{
    if (_mcr_inst)
        mclTerminateInstance(&_mcr_inst);
}

LIB_libBodyfat_C_API 
void MW_CALL_CONV libBodyfatPrintStackTrace(void) 
{
    char** stackTrace;
    int stackDepth = mclGetStackTrace(&stackTrace);
    int i;
    for(i=0; i<stackDepth; i++)
    {
        mclWrite(2 /* stderr */, stackTrace[i], sizeof(char)*strlen(stackTrace[i]));
        mclWrite(2 /* stderr */, "\n", sizeof(char)*strlen("\n"));
    }
    mclFreeStackTrace(&stackTrace, stackDepth);
}


LIB_libBodyfat_C_API 
bool MW_CALL_CONV mlxBodyfatFcn(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[])
{
    return mclFeval(_mcr_inst, "bodyfatFcn", nlhs, plhs, nrhs, prhs);
}

LIB_libBodyfat_C_API 
bool MW_CALL_CONV mlfBodyfatFcn(int nargout, mxArray** Y, mxArray** Xf, mxArray** Af, 
                                mxArray* X, mxArray* _U4b, mxArray* _U4c)
{
    return mclMlfFeval(_mcr_inst, "bodyfatFcn", nargout, 3, 3, Y, Xf, Af, X, _U4b, _U4c);
}
user790082
  • 69
  • 5
  • If Matlab has generated functions that are callable from C, then your problem is actually "how to call C routines from Fortran". The most appropriate way to do that is to use the C-Fortran interoperability features provided by the `ISO_C_BINDING` module. In short, you have to write in Fortran the interfaces for the C functions you want to call. If you post a C prototype example from one of your .h files, we can show you how to write the equivalent interface in Fortran. – PierU Feb 09 '23 at 11:13
  • Thank you for your answer. I updated the post by adding the content of .h and .c files. Are all those functions needed to be called? Matlab generates functions that were not in .m (matlab) file. If they all (libBodyfatInitialize, libBodyfatInitializeWithHandlers, libBodyfatTerminate, libBodyfatPrintStackTrace, mlxBodyfatFcn, mlfBodyfatFcn) have to be called, in which order that should be done? – user790082 Feb 09 '23 at 15:51

0 Answers0