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