For faster computations using FreeMAT...
Do the following 4 steps:
#define __PORT __declspec(dllexport) // Ex.1) Vector Operation (length N) __PORT void addArrays(int N, float *a, float *b, float *c){ int i; for(i=0;i<N;i++) c[i]=a[i]+b[i]; } // Ex.2) Matrix Operation (size NxM) __PORT void addMat(int N, int M, float __fastcall *a, float __fastcall *b, float __fastcall *c){ int i,j; for(i=0;i<N;i++) for(j=0;j<M;j++) c[i*M+j]=a[i*M+j]+b[i*M+j]; }
test1.m:
import('foo.dll','addArrays','addArrays','void','int32 N, float[N] a, float[N] b, float[N] &c'); import('foo.dll','addMat','addMat','void','int32 N, int32 M, float[N*M] a, float[N*M] b, float[N*M] &c'); a=[1,2,3,4]; b=[5,6,7,8]; c=zeros(1,length(a)); % c must be pre-defined d=[1,2;3,4]; e=[5,6;7,8]; f=zeros(size(d,1),size(d,2)); % f must be pre-defined addArrays(length(a),a,b,c); addMat(size(d,1),size(d,2),d,e,f); c,f
> bcc32 -WD -vu foo.c
This generates a shared library foo.dll in the current directory.
1) Clear from FreeMAT:--> clear 'libs'2) Unlock foo.dll (using freeware 'unlocker' etc.) from Windows OS (this still is required, due maybe to the bug of FreeMAT...) Or, simply restart FreeMAT.
--> test1 ans = 6 8 10 12 ans = 6 8 10 12 -->
Pointer variables cannot be returned to FreeMAT, but it is still possible to return a single value. The following function returns an integer value of ret to FreeMAT:
__PORT int foo(int a){ int ret,b=3; ret=a*2+b; return ret; }
In FreeMAT, you can retrieve the value as
--> import('foo.dll','foo','foo','int32','int32 a'); --> y=foo(3) ans = 9 -->
As in the on-line manual for import command, you can output messages to FreeMAT console within C functions by the following codes:
typedef void (*strfunc)(const char*); strfunc FreeMatText; __PORT void freemat_io_handler(strfunc printFunc){ FreeMatText = printFunc; }
The above should be written in front of the following example code:
char msg[2048]; __PORT void foo1(){ sprintf(msg,"Can you see me?\n"); FreeMatText(msg); } __PORT void foo2(const char *str){ FreeMatText(str); }
Then, in FreeMAT, you can type
--> import('foo.dll','foo1','foo1','void',''); --> import('foo.dll','foo2','foo2','void','string str'); --> foo1(); Can you see me? --> foo2('This appears in FreeMAT Console'); % somewhat it doesn't show ... --> foo2(sprintf('This finally appears in FreeMAT Console!\n')); This finally appears in FreeMAT Console! --> foo2(sprintf('Year!\nYeeaarr!!\n')); Year! Yeeaarr!! -->
In order to retrieve the strings from C functions, the string data (i.e. char []) in C functions should first be converted in an integer array (i.e. by casting them), and then, retrieved using integer pointer (i.e. using int * instead):
__PORT void foo3(int N, int *str){ char *b="[test1]\n[test2]"; int i,n=strlen(b); if(n>N)n=N; for(i=0;i<n;i++) str[i]=(int)b[i]; }
In FreeMAT, you need to convert the integer type values obtained from the C function back into string data type using char command:
--> import('foo.dll','foo3','foo3','void','int32 N, int32[N] &s'); --> str=zeros(1,20); --> foo3(length(str),str); char(str) ans = [test1] [test2] -->
The easiest way may be to take the following three steps:
An example C source:
char *str="{'test1';'test23'}"; // Example strings __PORT int getstr(int flg, int N, int *s){ int i,len=strlen(str); if(flg==1) for(i=0;i<N;i++) s[i]=(int)str[i]; else s[0]=0; return len; }
Then, in FreeMAT:
--> import('foo.dll','getstr','getstr','int32','int32 flg, int32 N, int32[N] &s'); --> d=0; % dummy variable --> len=getstr(0,1,d); % Note: here, the 2nd argument should be one --> d=zeros(1,len); --> getstr(1,len,d); --> e=eval(char(d)) e = [test1] [test23] --> e{1} ans = test1 --> e{2} ans = test23 -->
Here is a complete example. In this example, a double-type matrix can be dynamically loaded into the FreeMAT.
The C source code:
double **a; // The matrix data int nRows=0,nCols=0; // Variable numbers of rows and columns for a[][] char sMessage[2048]; // For showing a message on FreeMAT console __PORT int GetNRows(void){return nRows;} __PORT int GetNCols(void){return nCols;} __PORT int AddData(int N,double __fastcall *b){ int i; if(nRows==0){ nCols=N; a=(double **)calloc(1,sizeof(double *)); a[0]=(double *)calloc(N,sizeof(double)); for(i=0;i<N;i++) a[0][i]=b[i]; nRows++; }else{ if(N!=nCols){ sprintf(sMessage, "Input number of cols %d is different from the original %d!!\n",N,nCols); FreeMatText(sMessage); return -1; } a=realloc(a,(nRows+1)*sizeof(double *)); a[nRows]=calloc(N,sizeof(double)); for(i=0;i<N;i++) a[nRows][i]=b[i]; nRows++; } return GetNRows(); } __PORT void PrintData(void){ int i,j; for(i=0;i<nRows;i++){ for(j=0;j<nCols;j++){ sprintf(sMessage,"%d ",a[i][j]); FreeMatText(sMessage); } sprintf(sMessage,"\n"); FreeMatText(sMessage); } } __PORT int GetData(int N, int M, double __fastcall *b){ int i,j,n=N; if(M!=nCols){ sprintf(sMessage,"Input number of cols must be the same as %d!!\n",nCols); FreeMatText(sMessage); return -1; } if(N>nRows) n=nRows; for(i=0;i<n;i++) for(j=0;j<M;j++) b[j*n+i]=a[i][j]; // somewhat must be stored in this order... return GetNRows(); } __PORT void FreeData(void){ int i; for(i=0;i<nRows;i++) free(a[i]); free(a); nRows=nCols=0; }
test2.m:
if exist('AddData')==0 sDll='foo.dll'; % The import() below must not be called twice, unless 'foo.dll' is unlocked. % Otherwise, FreeMAT will crash... import(sDll,'AddData','AddData','int32','int32 N, double[N] dat'); import(sDll,'GetData','GetData','int32','int32 N, int32 M, double[N*M] &dat'); import(sDll,'GetNRows','GetNRows','int32',''); import(sDll,'GetNCols','GetNCols','int32',''); import(sDll,'PrintData','PrintData','void',''); import(sDll,'FreeData','FreeData','void',''); end fprintf('First of all, three rows are added into the shared memory'); AddData(3,[1.2 2.3 3.4]); AddData(3,[4.5 5.6 6.7]); AddData(3,[7.8 8.9 9.0]); r=GetNRows(); c=GetNCols(); dat=zeros(r,c); GetData(r,c,dat);dat fprintf('Then, another row is added into the shared memory'); AddData(3,[3.2 2.1 1.0]); r=GetNRows(); c=GetNCols(); dat=zeros(r,c); GetData(r,c,dat);dat FreeData(); % Call this, when 'dat' is no more needed.
Then, on FreeMAT console, execute it:
--> test2 First of all, three rows are added into the shared memory ans = 1.2000 2.3000 3.4000 4.5000 5.6000 6.7000 7.8000 8.9000 9.0000 Then, another row is added into the shared memory ans = 1.2000 2.3000 3.4000 4.5000 5.6000 6.7000 7.8000 8.9000 9.0000 3.2000 2.1000 1.0000 -->
1. On-line manual of FreeMAT(v4.0) - import command
Written by Tetsuya Hoya