7

MathematicaをC++で書かれた関数と統合することについて以前に質問がありました。

これはフォローアップの質問です:

計算に時間がかかりすぎる場合は、[評価]>[評価の中止]を使用して計算を中止できるようにしたいと思います。回答で提案されているテクノロジーのうち、割り込み可能なCベースの拡張機能を使用できるのはどれですか?C側で「割り込み性」をどのように実装できますか?

関数もMathematicaカーネルも破壊しない方法で関数を割り込み可能にする必要があります(つまり、関数が中断された後、Mathematicaから関数を再度呼び出すことができるはずです)

4

3 に答える 3

5

MathLinkベースの関数の場合、(Windowsの場合)2つのことを行う必要があります。MLAbortアボートをチェックするために使用することとMLCallYieldFunction、プロセッサを一時的に生成するためにを呼び出すことです。どちらも、Todd GayleyによるMathLinkチュートリアルで説明されており、ここから入手できます。

以前の回答のビットを使用して、素数を計算するためのサンプルコードを次に示します(非効率的な方法ですが、これが説明のためにここで必要なものです)。

code = 
"
#include <stdlib.h>

extern void primes(int n);

static void yield(){
    MLCallYieldFunction(
        MLYieldFunction(stdlink), 
        stdlink,
       (MLYieldParameters)0 );
}

static void abort(){
    MLPutFunction(stdlink,\" Abort \",0);
}

void primes(int n){
    int i = 0, j=0,prime = 1, *d = (int *)malloc(n*sizeof(int)),ctr = 0;    
    if(!d) {
       abort();
       return;
    }
    for(i=2;!MLAbort && i<=n;i++){
        j=2;
        prime = 1;      
        while (!MLAbort && j*j <=i){
            if(i % j == 0){
                prime = 0;
                break;
            }
            j++;
        }
        if(prime) d[ctr++] = i;
        yield();
    }
    if(MLAbort){
        abort();
        goto R1;
    }

    MLPutFunction(stdlink,\"List\",ctr);
    for(i=0; !MLAbort && i < ctr; i++ ){
        MLPutInteger(stdlink,d[i]);
        yield();        
    }
    if(MLAbort) abort();

 R1: free(d);
 }
 ";

およびテンプレート:

template = 
"
void primes P((int ));

:Begin:
:Function:       primes
:Pattern:        primes[n_Integer]
:Arguments:      { n }
:ArgumentTypes:  { Integer }
:ReturnType:     Manual
:End:
";

プログラムを作成するためのコードは次のとおりです(前の回答から取得、わずかに変更):

Needs["CCompilerDriver`"];
fullCCode = makeMLinkCodeF[code];
projectDir = "C:\\Temp\\MLProject1";
If[! FileExistsQ[projectDir], CreateDirectory[projectDir]]
pname = "primes";
files = MapThread[
   Export[FileNameJoin[{projectDir, pname <> #2}], #1, 
     "String"] &, {{fullCCode, template}, {".c", ".tm"}}];

ここで、それを作成します。

In[461]:= exe=CreateExecutable[files,pname];
Install[exe]

Out[462]= LinkObject["C:\Users\Archie\AppData\Roaming\Mathematica\SystemFiles\LibraryResources\
Windows-x86-64\primes.exe",161,10]

そしてそれを使用します:

In[464]:= primes[20]
Out[464]= {2,3,5,7,11,13,17,19}

In[465]:= primes[10000000]
Out[465]= $Aborted

後者の場合、Alt+"を使用しました。" 計算を中止します。への呼び出しを含めないと、これは正しく機能しないことに注意してくださいyield

一般的なイデオロギーは、大きなループなど、すべての高価な計算をチェックしMLAbortて呼び出す必要があるというものです。おそらく、上記のように内部ループに対してそれを行うのはやり過ぎです。MLCallYieldFunction試してみることができることの1つは、Cプリプロセッサ(マクロ)を使用してボイラープレートコードを因数分解することです。

于 2011-11-26T20:03:33.097 に答える
3

これまで試したことがないので、Expression Packet機能はこのように機能するようです-Cコードが戻って、数学に定期的に行う作業をさらに要求した場合、数学側で実行を中止すると、Cコードに次のように通知されますやるべきことはもうありません。

于 2011-11-26T15:48:15.697 に答える
3

LibraryLinkを使用して外部CコードをMathematicaカーネルにリンクしている場合は、Libraryコールバック関数AbortQを使用して、中止が進行中であるかどうかを確認できます。

于 2011-11-27T09:44:54.857 に答える