Scilab Website | Contribute with GitLab | Mailing list archives | ATOMS toolboxes
Scilab Online Help
5.5.1 - 日本語

Change language to:
English - Français - Português - Русский

Please note that the recommended version of Scilab is 2024.0.0. This page might be outdated.
See the recommended documentation of this function

Scilabヘルプ >> API Scilab > API_Scilab入門

API_Scilab入門

C, C++ またはfortranコードを新しい関数としてScilabエンジンに読み込む方法

説明

api_scilabプレゼンテーション で説明されたように, ScilabはC, C++またはFortranコード(ソースまたはライブラリ)で言語を 拡張するためのAPIを提供します.

Scilabエンジンとアプリケーションコードの間のリンクは gatewayと呼ばれます.

多くの場合, 処理は常に同じで,以下のようになります:

  1. ユーザに指定された(入力及び出力)引数の数を調べます.

    例えば,関数foo(x)foo() または foo(2,3)のようにコールされ, ユーザが答を得ます.

    詳細: CheckInputArgument および CheckOutputArgument

  2. 入力引数の管理

    複数の処理を行います:

    1. 入力引数Xの変数アドレスを取得します

      関数 SciErr getVarAddressFromPosition(void* context, int positionOfTheVariable, int** address)

    2. 変数の型を調べます: doubleの行列 (複素数または複素数以外), 文字列 , 等

      SciErr getVarType(void* context, int* positionOfTheVariable, int* Type)

      他の関数も提供されています:

      • int isBooleanType(void* context, int* address)

      • int isBooleanSparseType(void* context, int* address)

      • int isDoubleType(void* context, int* address)

      • int isIntegerType(void* context, int* address)

      • int isPointerType(void* context, int* address)

      • int isPolyType(void* context, int* address)

      • int isSparseType(void* context, int* address)

      • int isStringType(void* context, int* address)

      • int isListType(void* context, int* address)

      • int isTListType(void* context, int* address)

      • int isMListType(void* context, int* address)

    3. 関連する場合, 入力引数かどうかを確認します.

      int isVarComplex(void* context, int* address)

    4. 整数を処理する場合,さらに整数の精度も確認します

      SciErr getMatrixOfIntegerPrecision(void* context, int* address, int* precision)

    5. 変数の大きさを確認します: 正方行列, スカラー, 等

      大きさに関する情報を取得する際にも 実際のデータを取得する際に使用するものと同じ関数を使用します. 例えば, double の行列の場合 関数コール SciErr getMatrixOfDouble(void* context, int* address, int* nbRows, int* nbCols, double** theActualData) により行列の次元を取得できます.

      ほぼ全てのScilabデータ型にはこのような処理を行うための 同様なC関数があります.

    6. その他, 特定の値かどうかを調べたり, 最初と2番目の入力引数の間の整合性を 確認したりすること等も可能です.

    7. データ変換 (オプション).

      使用するコードまたはライブラリによっては, いくつかの変換をデータに適用することができます. 古典的な例は行列の記録を列形式から線形式に変換するものです.

      通常,このようにすると性能が低下することに注意してください.

  3. アプリケーションコード

    確認とデータ取得を行った後,実際の主コードをコールできます. 実際の情報処理(処理, データ変換, 等)をここで実行します.

    これは, src/c, src/cpp または src/fortranに保存,構築した サードパーティのコードにより行いますが, ライブラリ形式とすることも可能です. あらゆるライブラリをScilabにリンクすることができます.

  4. Scilabエンジンの出力引数を作成する

    通常,アプリケーションコードの実行後, 何らかのデータをScilabインタプリタから戻します.

    例えば, doubleの行列をScilabエンジンに保存する場合,C関数 SciErr createMatrixOfDouble(void* context, int position, int nbRows, int nbCols, const double* matrixOfDouble) をコールします.

    通常,位置は nbInputArgument(pvApiCtx) + Xにより取得できます. X が返す出力引数の位置となります. 例えば, 関数プロファイル [a, b, c] = foo(); nbInputArgument(pvApiCtx) + 3 は 変数cとなります.

    作成できる次元はゲートウェイの制約を受けることに注意してください.

    ほぼ全てのScilabデータ型はこのような処理を行う同様なC関数を有します.

  5. Scilabエンジンに出力引数を返す

    以下, タスク4で, 作成した変数を返します.

    aを返す 前の例 [a, b, c] = foo();の場合, 以下の宣言を行います: AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1;

    Scilabエンジンに新しい変数をコミットするには, 関数 ReturnArguments(pvApiCtx) をコールします.

ほぼ全てのAPI_Scilab関数がエラーに関する多くの情報を含む SciErrと呼ばれるC構造体を返すことに注意してください.

デフォルトでは, Scilab数値はC言語のdouble型に保存されます.

習慣的に, ゲートウェイは,sci_gateway/c/ (または /cpp/) に保存され,sci_functionName.cという名前が付けられます.

pvApiCtx は,グローバルコンテキスト変数です. これは,バージョン5系では使用されていませんが, Scilab バージョン 6で導入される マルチスレッド機能を管理するために導入されています.

実用的な例

以下のScilab関数を例として示します:

[c,d] = foo(a,b)

aはdouble行列,aと同じ大きさの bは論理値行列, foo はaの各要素に2を乗じて, cとして返します. また,bを要素毎に逆の論理値に変換して返します.

Scilabバイナリに含まれるツールボックススケルトンでサンプルを取得できます. パスは contrib/toolbox_skeleton/sci_gateway/c/sci_foo.cです.

詳細な説明は以下の例のCコメント形式で提供されています.

// 完全なソースはtoolboxスケルトンのsci_gateway/c/ ディレクトリにあります

// 標準ヘッダ
#include "api_scilab.h"
#include "BOOL.h"
// 関数宣言
int sci_foo(char *fname, unsigned long fname_len)
{
    // エラー管理変数
    SciErr sciErr;
    ////////// 変数宣言 //////////
    int m1 = 0, n1 = 0;
    int *piAddressVarOne = NULL;
    double *matrixOfDouble = NULL;
    double *newMatrixOfDouble = NULL;
    int m2 = 0, n2 = 0;
    int *piAddressVarTwo = NULL;
    int *matrixOfBoolean = NULL;
    int *newMatrixOfBoolean = NULL;
    int i = 0;
    ////////// 入力/出力引数の数を調べる //////////
    /* --> [c, d] = foo(a, b) */
    /* 入力引数が2のみであることを調べる */
    /* 出力引数が2のみであることを調べる */
    CheckInputArgument(pvApiCtx, 2, 2) ;
    CheckOutputArgument(pvApiCtx, 2, 2) ;
    ////////// 最初の入力引数 (double) を管理 //////////
    /* 入力アドレスを取得 */
    sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddressVarOne);
    if (sciErr.iErr)
    {
        printError(&sciErr, 0);
        return 0;
    }
    /* 最初の入力引数が実数行列(複素数でない)であることを調べる */
    if ( !isDoubleType(pvApiCtx, piAddressVarOne) ||  isVarComplex(pvApiCtx, piAddressVarOne) )
    {
        Scierror(999, "%s: Wrong type for input argument #%d: A real matrix expected.\n", fname, 1);
        return 0;
    }
    /* 行列を取得 */
    sciErr = getMatrixOfDouble(pvApiCtx, piAddressVarOne, &m1, &n1, &matrixOfDouble);
    if (sciErr.iErr)
    {
        printError(&sciErr, 0);
        return 0;
    }
    ////////// 2番目の入力引数を管理 (論理値) //////////
    /* 入力アドレスを取得 */
    sciErr = getVarAddressFromPosition(pvApiCtx, 2, &piAddressVarTwo);
    if (sciErr.iErr)
    {
        printError(&sciErr, 0);
        return 0;
    }
    if ( !isBooleanType(pvApiCtx, piAddressVarTwo) )
    {
        Scierror(999, "%s: Wrong type for input argument #%d: A boolean matrix expected.\n", fname, 2);
        return 0;
    }
    /* 行列を取得 */
    sciErr = getMatrixOfBoolean(pvApiCtx, piAddressVarTwo, &m2, &n2, &matrixOfBoolean);
    if (sciErr.iErr)
    {
        printError(&sciErr, 0);
        return 0;
    }
    ////////// 2つの入力引数の相関を確認 //////////
    if ((m1 != m2) || (n1 != n2))
    {
        Scierror(999, "%s: Wrong size for input arguments: Same size expected.\n", fname, 1);
        return 0;
    }
    newMatrixOfDouble = (double*)malloc(sizeof(double) * m1 * n1);
    ////////// アプリケーションコード //////////
    // ライブラリへのコールで置換することができます
    for (i = 0; i < m1 * n1; i++)
    {
        /* 行列の各要素を2倍します */
        newMatrixOfDouble[i] = matrixOfDouble[i] * 2;
    }
    newMatrixOfBoolean = (int*)malloc(sizeof(BOOL) * m2 * n2);
    for (i = 0; i < m2 * n2; i++)
    {
        /* 行列の各要素について, 値を反転する */
        newMatrixOfBoolean[i] = ((matrixOfBoolean[i] == TRUE) ? FALSE : TRUE);
    }
    ////////// 出力引数を作成 //////////
    /* 関数の戻り値として行列を作成 */
    sciErr = createMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 1, m1, n1, newMatrixOfDouble);
    free(newMatrixOfDouble); // データをScilabメモリにコピー
    if (sciErr.iErr)
    {
        free(newMatrixOfBoolean); // エラーの際,完全にクリンナップします
        printError(&sciErr, 0);
        return 0;
    }
    /* 関数の戻り値として行列を作成 */
    sciErr = createMatrixOfBoolean(pvApiCtx, nbInputArgument(pvApiCtx) + 2, m2, n2, newMatrixOfBoolean);
    free(newMatrixOfBoolean); // データをScilabメモリにコピー
    if (sciErr.iErr)
    {
        printError(&sciErr, 0);
        return 0;
    }
    ////////// 出力引数をScilabエンジンに戻す //////////
    AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1;
    AssignOutputVariable(pvApiCtx, 2) = nbInputArgument(pvApiCtx) + 2;
    return 0;
}

このコードを構築,Scilabにロードする際,Scilabの動的リンク機能を使用します. この組み込み処理はScilabに委任するため,以下のコードはマルチプラットフォーム対応です.

files=["sci_foo.c"];
// TODO: WTF ?
WITHOUT_AUTO_PUTLHSVAR = %t;
ilib_build('build_lib',['foo','sci_foo'],files,[]);
exec loader.sce
[c, d] = foo([2,%pi], [%t, %f])

種々の確認が行われます:

-->[c, d] = foo(2, 2)
                   !--error 999
foo: Wrong type for input argument #2: A boolean matrix expected.
-->[c, d] = foo([2,2], %t)
                        !--error 999
foo: Wrong size for input arguments: Same size expected.
-->[a,b]=foo(2+%i,%t)
                   !--error 999
foo: Wrong type for input argument #1: A real matrix expected.
-->[c, d] = foo([2,%pi], [%t, %f])
 d  =

  F T
 c  =

    4.    6.2831853

Report an issue
<< api_scilab API Scilab call_scilab API >>

Copyright (c) 2022-2023 (Dassault Systèmes)
Copyright (c) 2017-2022 (ESI Group)
Copyright (c) 2011-2017 (Scilab Enterprises)
Copyright (c) 1989-2012 (INRIA)
Copyright (c) 1989-2007 (ENPC)
with contributors
Last updated:
Thu Oct 02 13:58:35 CEST 2014