We have the following C function matmul
which performs
a matrix multiplication. Only the calling sequence is important.
/*Matrix multiplication C=A*B, (A,B,C stored columnwise) */ #define A(i,k) a[i + k*n] #define B(k,j) b[k + j*m] #define C(i,j) c[i + j*n] void matmul(a,n,m,b,l,c) double a[],b[],c[]; int n,m,l; { int i,j,k; double s; for( i=0 ; i < n; i++) { for( j=0; j < l; j++) { s = 0.; for( k=0; k< m; k++) { s += A(i,k)*B(k,j); } C(i,j) = s; } } }
We want to have a new Scilab function (also called matmul
)
which is such that the Scilab command
-->C=matmul(A,B)returns in
C
the matrix product A*B
computed
by the above C function. Here A, B
and C
are standard
numeric Scilab matrices. Thus, the Scilab matrices A
and B
should be sent to the C function matmul
and the matrix
C
should be created, filled, and sent back to Scilab.
To create the Scilab function matmul
, we have to write
the following C gateway function called
intmatmul
. See the file
SCIDIR/examples/interface-tutorial/intmatmul.c
.
#include "stack-c.h" int intmatmul(fname) char *fname; { static int l1, m1, n1, l2, m2, n2, l3; static int minlhs=1, maxlhs=1, minrhs=2, maxrhs=2; /* Check number of inputs (Rhs=2) and outputs (Lhs=1) */ CheckRhs(minrhs,maxrhs) ; CheckLhs(minlhs,maxlhs) ; /* Get A (#1) and B (#2) as double ("d") */ GetRhsVar(1, "d", &m1, &n1, &l1); GetRhsVar(2, "d", &m2, &n2, &l2); /* Check dimensions */ if (!(n1==m2)) {Scierror(999,"%s: Uncompatible dimensions\r\n",fname); return 0;} /* Create C (#3) as double ("d") with m1 rows and n1 columns */ CreateVar(3, "d", &m1, &n2, &l3); /* Call the multiplication function matmul inputs:stk(l1)->A, stk(l2)->B output:stk(l3)->C */ matmul(stk(l1), m1, n1, stk(l2), n2, stk(l3)); /* Return C (3) */ LhsVar(1) = 3; return 0; }
Let us now explain each step of the gateway function intmatmul
.
The gateway function must include the file SCIDIR/routines/stack-c.h
.
This is the first line of the file.
The name of the routine is intmatmul
and it admits one input parameter which is fname
.
fname
must be declared as char *
. The name of the gateway
routine (here intmatmul
) is arbitrary but the parameter
fname
is compulsory.
The gateway routine then includes the declarations of the C variables used.
In the gateway function intmatmul
the Scilab matrices
A
, B
and C
are referred to as numbers,
respectively 1
, 2
and 3
.
The line
CheckRhs(minrhs,maxrhs); CheckLhs(minlhs,maxlhs);is to check that the Scilab function
matmul
is called with
a correct number of RHS and LHS parameters. For instance, typing
-->matmul(A)
will give an error message made by CheckRhs
.
The function CheckRhs
just compares the C variable Rhs
(transmitted in the include file stack-c.h
) with the bounds
minrhs
and maxrhs
.
The next step is to deal with the Scilab variables A
, B
and C
. In a gateway function, all the Scilab variables
are referred to as numbers. Here, the Scilab matrices
A
, B
and C
are
respectively numbered 1
, 2
and 3
.
Each input variable of the newly created Scilab function
matmul
(i.e. A
and B
)
should be processed by a call to GetRhsVar
.
The first two parameters of GetRhsVar
are inputs and the last
three parameters are outputs.
The line
GetRhsVar(1, "d", &m1, &n1, &l1);means that we process the RHS variable numbered
1
(i.e. A
).
The first parameter of GetRhsVar
(here 1
) refers to the
first parameter (here A
) of the Scilab function matmul
.
This variable is a Scilab numeric matrix which should be seen ("d") as a
double
C array, since the C routine matmul
is
expecting a double
array. The second parameter of GetRhsVar
(here "d"
) refers to the type (double, int, char etc) of the variable.
From the call to GetRhsVar
we know that A
has
m1
rows and n1
columns.
The line
if (n1 !=m2 ) {Scierror(999,"%s: Uncompatible dimensions\r\n",fname); return 0;}is to make a return to Scilab if the matrices
A
and B
passed to matmul
have uncompatible dimensions. The number
of columns of A
should be equal to the number of rows of B
.
The next step is to create the output variable C
. This is done by
CreateVar(3, "d", &m1, &n2, &l3);Here we create a variable numbered
3
(1
was for A
and 2
was for B
). It is an array of double ("d"
).
It has m1
rows and n2
columns.
The calling sequence of CreateVar
is the same as the calling sequence
of GetRhsVar
, but the four first parameters of CreateVar
are inputs.
The next step is the call to matmul
. Remember the calling sequence :
void matmul(a,n,m,b,l,c) double a[],b[],c[]; int n,m,l;We must send to this function (double) pointers to the numeric data in
A
, B
and C
.
This is done by :
matmul(stk(l1), m1, n1, stk(l2), n2, stk(l3));Here
stk(l1)
is a double pointer to the content of the A
matrix. The entries of the A
matrix are stored columnwise
in stk(l1)[0]
, stk(l1)[1]
etc.
Similarly, after the call to the C function matmul
the (double) numbers
stk(l3)[0]
, stk(l3)[1]
are the values of the
matrix product A*B
stored columnwise as computed by
matmul
.
The last parameter of the functions GetRhsVar
and CreateVar
is an output parameter which allow to access the data through a
pointer (here the double pointers stk(l1)
, stk(l2)
and
stk(l3)
.
The final step is to return the result, i.e. the C
matrix to Scilab.
This is done by
LhsVar(1) = 3;This statement means that the first LHS variable of the Scilab function
matmul
is the variable numbered 3
.
Once the gateway routine is written, it should be compiled, linked with Scilab and a script file should be executed in Scilab for loading the new function.
It is possible to build a static or a dynamic library. The static library
corresponding the the example just described here is built in the directory
SCIDIR/examples/interface-tutorial
and the dynamic library is built
into the directory SCIDIR/examples/interface-tutorial-so
.