cubuntuscilab

How to solve equations in Scilab API


I don't understand what the error is in calculating the system of linear equations. I need to solve a system of linear equations using the Scilab API in C, but I'm getting values that are too small. Checked the solution, the answer should be: [0;1]. Free is specially commented because the program crashes immediately.

I thought the error was in dgesv_, but it's strange since it's a Scilab function and why it's solved incorrectly. Maybe something is wrong with the output?

Code:

#include "api_scilab.h"
#include "Scierror.h"
#include "BOOL.h"
#include "localization.h"

extern void dgesv_(int* n, int* nrhs, double* A, int* lda, int* ipiv, double* b, int* ldb, int* info);

static const char fname[] = "foo6";

int sci_foo6(scilabEnv env, int nin, scilabVar* in, int nopt, scilabOpt* opt, int nout, scilabVar* out)
{
    int i = 0;
    int n = 0; // System dimension
    double* A = NULL; // Coefficient matrix
    double* b = NULL; // Right-hand side vector
    double* x = NULL; // Solution
    int info = 0;

    /* Check the number of input and output arguments */
    if (nin != 2 || nout != 1) {
        Scierror(77, _("%s: Wrong number of input or output arguments: 2 inputs and 1 output expected.\n"), fname);
        return 1;
    }

    /* Check the types of input arguments */
    if (scilab_isDouble(env, in[0]) == 0 || scilab_isMatrix2d(env, in[0]) == 0 ||
        scilab_isComplex(env, in[0]) == 1 || scilab_isDouble(env, in[1]) == 0 ||
        scilab_isMatrix2d(env, in[1]) == 0 || scilab_isComplex(env, in[1]) == 1) {
        Scierror(999, _("%s: Wrong type for input arguments. Double matrices expected.\n"), fname);
        return 1;
    }

    /* Get the dimension of the coefficient matrix */
    int rowA = 0, colA = 0, rowB = 0, colB = 0;
    scilab_getDim2d(env, in[0], &rowA, &colA);
    scilab_getDim2d(env, in[1], &rowB, &colB);
    if (rowA != colA || rowB != rowA || colB != 1) {
        Scierror(999, _("%s: Incorrect dimensions. Coefficient matrix should be square and vector should be a column vector of the same size.\n"), fname);
        return 1;
    }
    n = rowA;

    /* Get data from input arguments */
    scilab_getDoubleArray(env, in[0], &A);
    scilab_getDoubleArray(env, in[1], &b);

    /* Solve the system of linear equations */
    x = (double*)malloc(n * sizeof(double));
    dgesv_(&n, &n, A, &n, b, x, &n, &info);
    if (info != 0) {
        Scierror(999, _("%s: LAPACK dgesv function failed with error code %d.\n"), fname, info);
        free(x);
        return 1;
    }

    /* Create the output argument and copy the result */
    out[0] = scilab_createDoubleMatrix2d(env, 1, n, 0);
    double* xPtr = NULL;
    scilab_getDoubleArray(env, out[0], &xPtr);

    for (i = 0; i < n; i++) {
        xPtr[i] = x[i];
    }

    //free(x);
    return 0;
}

Conclusion:

--> A = [2, 1; -1, 2]; 
 
--> b = [1; 2]; 
 
--> x = foo6(A, b); 
 
--> disp(x); 
 
   5.27D-314   2.64D-314

Tried solving the SLAU through the Scilab API, but didn't get much out of it. I'm not sure if I'm doing it right.


Solution

  • See the below fixed code, yours above had several issues:

    1. Second argument of dgesv has to be equal to one
    2. The integer pivots array was missing
    3. The right hand side b is overwritten with the solution, hence you have to make a copy of initial b into x.
    #include "api_scilab.h"
    #include "Scierror.h"
    #include "BOOL.h"
    #include "localization.h"
    
    extern void dgesv_(int* n, int* nrhs, double* A, int* lda, int* ipiv, double* b, int* ldb, int* info);
    
    static const char fname[] = "foo6";
    
    int sci_foo6(scilabEnv env, int nin, scilabVar* in, int nopt, scilabOpt* opt, int nout, scilabVar* out)
    {
        int i = 0;
        int n = 0; // System dimension
        int iOne = 1;
        double* A = NULL; // Coefficient matrix
        double* b = NULL; // Right-hand side vector
        double* x = NULL; // Solution
        int* iPiv = NULL;
        int info = 0;
    
        /* Check the number of input and output arguments */
        if (nin != 2 || nout != 1) {
            Scierror(77, _("%s: Wrong number of input or output arguments: 2 inputs and 1 output expected.\n"), fname);
            return 1;
        }
    
        /* Check the types of input arguments */
        if (scilab_isDouble(env, in[0]) == 0 || scilab_isMatrix2d(env, in[0]) == 0 ||
            scilab_isComplex(env, in[0]) == 1 || scilab_isDouble(env, in[1]) == 0 ||
            scilab_isMatrix2d(env, in[1]) == 0 || scilab_isComplex(env, in[1]) == 1) {
            Scierror(999, _("%s: Wrong type for input arguments. Double matrices expected.\n"), fname);
            return 1;
        }
    
        /* Get the dimension of the coefficient matrix */
        int rowA = 0, colA = 0, rowB = 0, colB = 0;
        scilab_getDim2d(env, in[0], &rowA, &colA);
        scilab_getDim2d(env, in[1], &rowB, &colB);
        if (rowA != colA || rowB != rowA || colB != 1) {
            Scierror(999, _("%s: Incorrect dimensions. Coefficient matrix should be square and vector should be a column vector of the same size.\n"), fname);
            return 1;
        }
        n = rowA;
    
        /* Get data from input arguments */
        scilab_getDoubleArray(env, in[0], &A);
        scilab_getDoubleArray(env, in[1], &b);
    
        /* Solve the system of linear equations */
        x = (double*)malloc(n * sizeof(double));
        for (i = 0; i < n; i++) {
            x[i] = b[i];
        }
    
        iPiv = (int*)malloc(n * sizeof(int));
        dgesv_(&n, &iOne, A, &n, iPiv, x, &n, &info);
        if (info != 0) {
            Scierror(999, _("%s: LAPACK dgesv function failed with error code %d.\n"), fname, info);
            free(x);
            free(iPiv);
            return 1;
        }
    
        /* Create the output argument and copy the result */
        out[0] = scilab_createDoubleMatrix2d(env, 1, n, 0);
        double* xPtr = NULL;
        scilab_getDoubleArray(env, out[0], &xPtr);
    
        for (i = 0; i < n; i++) {
            xPtr[i] = x[i];
        }
    
        free(x);
        free(iPiv);
        return 0;
    }
    

    Instructions to compile and link were not given (the source above is supposed to be saved in sci_foo6.c):

     ilib_build('foo6',['foo6','sci_foo6','csci6'],"sci_foo6.c",[]);
     exec loader.sce
    

    Then the solution is correctly computed:

    --> A = [2, 1; -1, 2]; 
    
    --> b = [1;2];
    
    --> x = foo6(A,b)
     x  = 
    
       0.   1.