This is documentation for Mathematica 4, which was
based on an earlier version of the Wolfram Language.
View current documentation (Version 11.1)

 Documentation /  Mathematica /  Das Mathematica Buch /  Die Prinzipien von Mathematica /  MathLink und externe Programm-Kommunikation /

Anpassung externer, in Mathematica aufrufbarer FunktionenSpezialthema: Portabilität von MathLink-Programmen

2.12.4 Behandlung von Listen, Arrays und anderen Ausdrücken

Mittels MathLink können Daten jeglichen Typs mit externen Programmen ausgetauscht werden. Für gebräuchlichere Datentypen sind einfach nur geeignete :ArgumentTypes:- oder :ReturnType:-Spezifikationen in der MathLink-Schablonen-Datei anzugeben.

Grundlegende Typ-Spezifikationen

Hier ist die MathLink-Schablone für eine Funktion, die eine Liste von ganzen Zahlen als ihre Argumente verwendet.

:Begin:

:Function: h

:Pattern: h[a_List]

:Arguments: a

:ArgumentTypes: IntegerList

:ReturnType: Integer

:End:

Hier ist der C-Quellcode für die Funktion. Beachten Sie das zusätzliche Argument alen, mit dem die Länge der Liste übergeben wird.

int h(int *a, long alen)



int i, tot=0;



for(i=0; i<alen; i++)

tot += a[i];



return tot;

Dies installiert ein externes Programm, das Spezifikationen für die Funktion h enthält.

In[1]:= Install["hprog"]

Out[1]=

Dies ruft den externen Code auf.

In[2]:= h[{3, 5, 6}]

Out[2]=

Dies paßt nicht zum Muster h[a_List] und ruft deshalb nicht den externen Code auf.

In[3]:= h[67]

Out[3]=

Es wird eine Übereinstimmung mit dem Muster erreicht, aber die Elemente in der Liste haben für den externen Code den falschen Typ. Somit wird $Failed zurückgegeben.

In[4]:= h[{a, b, c}]

Out[4]=

Die Grundtypen der Argumente können beliebig miteinander gemischt werden. Wenn jedoch IntegerList oder RealList verwendet werden, muß in das C-Programm ein zusätzliches Argument eingefügt werden, um die Länge der Liste darzustellen.

Hier ist eine :ArgumentTypes:-Spezifikation.

:ArgumentTypes: IntegerList, RealList, Integer

Hier ist eine mögliche, entsprechende C-Funktionsdeklaration.

void f(int *a, long alen, double *b, long blen, int c)

Beachten Sie: Wenn durch MathLink eine Liste an ein C-Programm weitergegeben wird, so wird angenommen, daß sich deren erstes Argument an Position 0, wie es Standard in C ist, befindet, und nicht an Position 1, wie es Standard in Mathematica ist.

Hinzu kommt, folgt man dem C-Standard, daß Zeichenketten, die durch String spezifiziert sind, als char *-Objekte übergeben werden, die durch \0-Nullbytes terminiert werden. Abschnitt 2.12.5 erläutert, wie mit Sonderzeichen umzugehen ist.

MathLink-Funktionen zum Senden von Daten zu Mathematica

Wenn eine MathLink-Schablonen-Datei verwendet wird, erzeugen mprep und mcc im Grunde ein C-Programm, das explizite Aufrufe von MathLink-Bibliotheks-Funktionen enthält. Wenn Sie verstehen wollen, wie MathLink funktioniert, können Sie sich den Quellcode dieses Programmes anschauen. Beachten Sie, wenn Sie mcc verwenden, daß in der Regel eine -g-Option angegeben sein muß, anderenfalls wird der erzeugte Quellcode automatisch gelöscht.

Wenn die externe Funktion lediglich eine einzelne ganze Zahl oder eine einzelne Gleitpunktzahl zurückgibt, dann kann man dies in der MathLink-Schablonen-Datei einfach durch Angabe von Integer oder Real als :ReturnType: spezifizieren. Aufgrund der Weise, in der Zuweisung und Freigabe von Speicher in C funktionieren, kann aber die :ReturnType:-Spezifikationen, wie IntegerList oder RealList, nicht direkt angegeben werden. Um nun aber derartige Strukturen zurückzugeben, müssen stattdessen explizit in Ihrem C-Programm die MathLink-Bibliotheks-Funktionen aufgerufen und Manual als :ReturnType:-Spezifikation angegeben werden.

Hier ist die MathLink-Schablone einer Funktion, die eine ganze Zahl als Argument verwendet und ihren Funktionswert unter Verwendung expliziter MathLink-Funktionen zurückgibt.

:Begin:

:Function: bits

:Pattern: bits[i_Integer]

:Arguments: i

:ArgumentTypes: Integer

:ReturnType: Manual

:End:

Die Funktion ist als void deklariert.

void bits(int i) {



int a[32], k;

Dies legt Werte in das C-Array a.

for(k=0; k<32; k++)

a[k] = i%2;

i >>= 1;

if (i==0) break;





if (k<32) k++;

Dies sendet k Elemente des Arrays a zurück zu Mathematica.

MLPutIntegerList(stdlink, a, k);

return ;

}

Dies installiert das Programm, das die externe Funktion bits enthält.

In[5]:= Install["bitsprog"]

Out[5]=

Die externe Funktion liefert nun eine Liste von Bits.

In[6]:= bits[14]

Out[6]=

Wenn Sie in C ein Array durch int a[n1][n2][n3] deklarieren, dann können Sie es mit MLPutIntegerArray() als Liste mit der Tiefe 3 zu Mathematica senden.

...

Hier ist eine Deklaration für ein 3-dimensionales C-Array.

int a[8][16][100];

So wird das Array dims konstruiert und auf die Dimensionen von a initialisiert.

long dims[] = 8, 16, 100;

...

Dies sendet das 3-dimensionale Array a zu Mathematica, wobei eine Liste der Tiefe 3 erzeugt wird.

MLPutIntegerArray(stdlink, a, dims, NULL, 3);

...

Mit MathLink-Funktionen läßt sich absolut jeder Mathematica-Ausdruck erstellen. Die Grundidee dabei ist, eine Folge von MathLink-Funktionen aufzurufen, die direkt der FullForm-Darstellung des Mathematica-Ausdrucks entsprechen.

Dies richtet die Mathematica-Funktion Plus mit 2 Argumenten ein.

MLPutFunction(stdlink, "Plus", 2);

Dies spezifiziert, daß das erste Argument die ganze Zahl 77 ist.

MLPutInteger(stdlink, 77);

Und dies spezifiziert, daß das zweite Argument das Symbol x ist.

MLPutSymbol(stdlink, "x");

Im allgemeinen wird zuerst MLPutFunction() aufgerufen und der Kopf der Mathematica-Funktion, die erstellt werden soll, sowie die Anzahl ihrer Argumente angegeben. Dann werden andere MathLink-Funktionen aufgerufen, um jedes dieser Argumente der Reihe nach dort einzufügen. Abschnitt 2.1 geht auf die allgemeine Struktur von Mathematica-Ausdrücken und den Begriff Kopf ein.

Dies erzeugt eine Mathematica-Liste mit 2 Elementen.

MLPutFunction(stdlink, "List", 2);

Das erste Element der Liste ist eine Liste mit 10 ganzen Zahlen aus dem C-Array r.

MLPutIntegerList(stdlink, r, 10);

Das zweite Element der Hauptliste ist selbst eine Liste mit 2 Elementen.

MLPutFunction(stdlink, "List", 2);

Das erste Element dieser Unterliste ist eine Gleitpunktzahl.

MLPutReal(stdlink, 4.5);

Das zweite Element ist eine ganze Zahl.

MLPutInteger(stdlink, 11);

Mit MLPutIntegerArray() und MLPutRealArray() können Arrays gesendet werden, die in der eindimensionalen Weise, in der C diese Arrays vorher einordnet, im Speicher liegen. Wenn aber Arrays während der Ausführung eines C-Programms erzeugt werden, ist es üblicher, sie als verschachtelte Zeiger-Sätze zu konstruieren. Mit einer Folge von MLPutFunction()-Aufrufen, die mit einem MLPutIntegerList()-Aufruf beendet wird, können solche Arrays an Mathematica übergeben werden.

...

Dies deklariert a als eine verschachtelte Liste von Listen, die wiederum Listen von ganzen Zahlen enthalten.

int ***a;

...

Dies erzeugt eine Mathematica-Liste mit n1 Elementen.

MLPutFunction(stdlink, "List", n1);

for (i=0; i<n1; i++) {

Dies erstellt eine Unterliste mit n2 Elementen.

MLPutFunction(stdlink, "List", n2);

for (j=0; j<n2; j++) {

Dies schreibt Listen ganzer Zahlen.

MLPutIntegerList(stdlink, a[i][j], n3);

}

}

...

Man sollte wissen, daß jeder Ausdruck, den man mit MathLink-Funktionen erzeugt, evaluiert wird, sobald er zu Mathematica gesandt wird. Das bedeutet: Wenn man zum Beispiel ein Array transponieren will, das man Mathematica zurücksendet, muß man lediglich den Ausdruck, der das Array repräsentiert, in Transpose einhüllen. Dies erreicht man, indem man einfach MLPutFunction(stdlink, "Transpose", 1); aufruft und dann sofort den Ausdruck erzeugt, der das Array repräsentiert.

Die Idee der Nachbearbeitung von Daten, die man Mathematica zurücksendet, hat viele Anwendungen. Ein Beispiel ist die Methode zum Senden von Listen, deren Länge man vorher nicht kennt.

Dies erzeugt eine Mathematica-Liste durch explizites Anfügen von weiteren Elementen.

In[7]:= t = {}; Do[t = Append[t, i^2], {i, 5}]; t

Out[7]=

Dies erzeugt eine Liste, in der sich jedes nachfolgende Element in einer geschachtelten Unterliste befindet.

In[8]:= t = {}; Do[t = {t, i^2}, {i, 5}]; t

Out[8]=

Flatten ebnet die Liste ein.

In[9]:= Flatten[t]

Out[9]=

Sequence ebnet sich automatisch selbst ein.

In[10]:= {Sequence[1, Sequence[4, Sequence[ ]]]}

Out[10]=

Um MLPutIntegerList() aufzurufen, muß man die Länge der Liste kennen, die man senden will. Dies läßt sich jedoch vermeiden, indem man eine Folge verschachtelter Sequence-Objekte konstruiert.

Dies konstruiert die Liste um das Ergebnis herum.

MLPutFunction(stdlink, "List", 1);

while( bedingung ) {

erzeuge ein Element

Erzeuge die nächste Sequence-Objekt-Ebene.

MLPutFunction(stdlink, "Sequence", 2);

Übergib das Element.

MLPutInteger(stdlink, i );

}

Dies schließt das letzte Sequence-Objekt.

MLPutFunction(stdlink, "Sequence", 0);

Grundfunktionen zum expliziten Holen von Daten aus Mathematica

So wie MathLink Funktionen bereitstellt, wie zum Beispiel MLPutInteger(), um Daten von einem externen Programm zu Mathematica zu senden, so bietet es auch Funktionen, wie MLGetInteger(), mit denen Daten aus Mathematica in ein externes Programm geholt werden können.

Die Liste, die in einer MathLink-Schablone für :ArgumentTypes: angegeben wird, kann mit Manual abgeschlossen werden, um zu kennzeichnen, daß MathLink-Funktionen aufgerufen werden sollen, um zusätzliche Ausdrücke zu holen, nachdem andere Argumente empfangen worden sind.

:Begin:

:Function: f

Die Funktion f in Mathematica verwendet 3 Argumente.

:Pattern: f[i_Integer, x_Real, y_Real]

Alle diese Argumente werden direkt zum externen Programm weitergereicht.

:Arguments: i, x, y

Nur das erste Argument wird direkt zur externen Funktion gesandt.

:ArgumentTypes: Integer, Manual

:ReturnType: Real

:End:

Die externe Funktion benötigt lediglich ein explizites Argument.

double f(int i) {

Dies deklariert die Variablen x und y.

double x, y;

MLGetReal() holt explizit Daten vom Link.

MLGetReal(stdlink, &x);

MLGetReal(stdlink, &y);

return i+x+y;

}

MathLink-Funktionen, wie zum Beispiel MLGetInteger(link, pi), arbeiten sehr ähnlich wie die Standard-C-Bibliotheksfunktionen, wie zum Beispiel fscanf(fp, "%d", pi). Das erste Argument spezifiziert den Link, von dem die Daten geholt werden sollen. Das letzte Argument liefert die Adresse, an der die Daten, die erhalten werden, gespeichert werden sollen.

Holen einer Funktion via MathLink

:Begin:

:Function: f

Die Funktion f in Mathematica verwendet eine Liste von ganzen Zahlen als ihr Argument.

:Pattern: f[a:___Integer]

Die Liste wird direkt zum externen Programm weitergereicht.

:Arguments: a

Das Argument ist manuell durch das externe Programm zu holen.

:ArgumentTypes: Manual

:ReturnType: Integer

:End:

Die externe Funktion verwendet keine expliziten Argumente.

int f(void) {

Dies deklariert lokale Variablen.

long n, i;

int a[MAX];

Dies überprüft, ob die gesandte Funktion eine Liste ist, und speichert die Anzahl ihrer Elemente in n.

MLCheckFunction(stdlink, "List", &n);

Dies holt jedes Element in der Liste und speichert es in a[i].

for (i=0; i<n; i++)

MLGetInteger(stdlink, a+i);

...

}

In einfachen Fällen läßt sich normalerweise auf der Mathematica-Seite sicherstellen, daß die Daten, die zu einem externen Programm gesendet werden, die erwartete Struktur besitzen. Im allgemeinen wird aber der Rückgabewert von MLCheckFunction() nur dann ungleich Null sein, wenn die Daten aus einer Funktion bestehen, deren Name von Ihnen spezifiziert ist.

Beachten Sie: Wenn man eine verschachtelte Sammlung von Listen oder anderer Objekte erhalten möchte, kann man dies durch Erzeugen einer geeigneten Folge von MLCheckFunction()-Aufrufen erreichen.

Holen von Listen von Zahlen

Wenn ein externes Programm Daten von Mathematica erhält, muß es Platz zum Speichern der Daten reservieren. Wenn die Daten aus einer ganzen Zahl bestehen, wie bei MLGetInteger(stdlink, &n), dann genügt es, wenn diese ganze Zahl einfach durch int n deklariert wurde.

Wenn die Daten aber eine möglicherweise beliebige lange Liste von ganzen Zahlen enthalten, muß Speicher zugewiesen werden, um diese Liste zu dem Zeitpunkt zu speichern, an dem das externe Programm tatsächlich aufgerufen wird.

MLGetIntegerList(stdlink, &a, &n) führt diese Zuweisung automatisch durch und setzt a gleich einem Zeiger auf das Ergebnis. Zu beachten ist, daß Speicher, der durch Funktionen wie MLGetIntegerList() reserviert wird, sich immer in einem speziellen reservierten Bereich befindet; deshalb kann er nicht direkt modifiziert oder freigegeben werden.

Hier ist ein externes Programm, zu dem eine Liste von ganzen Zahlen gesendet wird.

int f(void) {

Dies deklariert lokale Variablen. a ist ein Array von ganzen Zahlen.

long n;

int *a;

Dies holt eine Liste von ganzen Zahlen und macht a zu einem Zeiger auf das Ergebnis.

MLGetIntegerList(stdlink, &a, &n);

...

Dies gibt den Speicher frei, der verwendet wurde, um die Liste von ganzen Zahlen zu speichern.

MLDisownIntegerList(stdlink, a, n);

...

}

Wird IntegerList als eine :ArgumentTypes:-Spezifikation verwendet, dann wird MathLink automatisch den Speicher, der für die Liste verwendet wird, freigeben, nachdem das externe Programm beendet ist. Wenn aber durch explizite Verwendung von MLGetIntegerList() eine Liste von ganzen Zahlen erhalten wurde, dann darf nicht vergessen werden, den Speicher, der zur Speicherung der Liste verwendet wird, freizugeben, sobald die Liste nicht mehr benötigt wird.

Holen von Arrays von Zahlen

MLGetIntegerList() extrahiert ein eindimensionales Array aus einer einzelnen Mathematica-Liste. MLGetIntegerArray() extrahiert ein Array von ganzen Zahlen aus einem Satz Listen oder anderer Mathematica-Funktionen, die bis zu einer beliebigen Tiefe verschachtelt sind.

Der Name der Mathematica-Funktion auf der Ebene i in der Struktur, wird in köpfe[i] als Zeichenkette gespeichert. Die Größe der Struktur auf der Ebene i wird in dims[i] gespeichert, während die Gesamttiefe in d gespeichert wird.

Wenn Sie Ihrem externen Programm eine Liste von komplexen Zahlen übergeben, dann erzeugt MLGetRealArray() ein zweidimensionales Array, das eine Folge von Paaren mit Real- und Imaginärteil enthält. In diesem Fall ist köpfe[0] "List", während köpfe[1] "Complex" ist.

Beachten Sie, daß Sie auf bequeme Weise mit externen Programmen beliebig genaue Zahlen austauschen können, indem Sie sie in Mathematica mit IntegerDigits und RealDigits in eine Liste von Ziffern umwandeln.

Holen von Zeichenketten und Symbolnamen

Wird String als eine :ArgumentTypes:-Spezifikation verwendet, dann wird MathLink den Speicher, der zum Speichern der Zeichenkette verwendet wird, automatisch freigeben, sobald die Funktion abgearbeitet wurde. Das bedeutet: Wenn weiterhin auf die Zeichenkette verwiesen werden soll, dann muß hierfür Speicher zugeordnet und jedes Zeichen der Zeichenkette explizit hineinkopiert werden.

Erhält man jedoch mit MLGetString() eine Zeichenkette, dann wird MathLink den für die Zeichenkette verwendeten Speicher nicht automatisch freigeben, sobald die Funktion endet. Deshalb kann man weiterhin auf die Zeichenkette verweisen. Wenn die Zeichenkette nicht mehr länger benötigt wird, muß MLDisownString() explizit aufgerufen werden, um den mit ihr verknüpften Speicher freizumachen.

Holen einer beliebigen Funktion

Wenn man weiß, welche Funktion im externen Programm zu erwarten ist, dann ist es normalerweise einfacher, MLCheckFunction() aufzurufen. Wenn man dies aber nicht weiß, hat man keine andere Wahl, als MLGetFunction() aufzurufen. Dann wiederum muß sichergestellt werden, daß MLDisownSymbol() aufgerufen wird, um den mit dem Funktionsnamen, der durch MLGetFunction() ermittelt wurde, verknüpften Speicher freizugeben.

Anpassung externer, in Mathematica aufrufbarer FunktionenSpezialthema: Portabilität von MathLink-Programmen