6.2.2 Example

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`

.