Funktionen auf Strukturen der Linearen Algebra
Einführung
Notation von Vektoren, Matrizen, Tensoren
Im Math Modul werden mehrdimensionale Strukturen nicht nur für Berechnungen benötigt, sie sind vielmehr auch ein möglicher Ergebnistyp von Funktionen, die nicht nur einen skalaren Wert liefern. Beispiel hierfür sind String-Funktionen, die in einem Text bestimmte Muster suchen. Alle Treffer-Positionen und Längen werden dann in einer Matrix zurückgegeben.
Grundsätzlich können Vektoren, Matrizen und Tensoren im Math Modul mittels der [ ... ]
Syntax erzeugt werden. Alle numerischen Datentypen sind möglich, jedoch kein <str>
. Als Elemente können Terme, Konstanten oder auch Inhalte von anderen Variablen verwendet werden. Der Datentyp der Struktur ist immer derjenige, in dem alle Elemente bestmöglich darstellbar sind.
Beispiele sind:
num = 3.14159; // example for a variable as source
vec = [1, -2, false, num, 5]; // data type is <dbl> to represent num
mat = [ [ 1.1, num ] // 1st row
, [-num, 2.2 ] // 2nd row
, [ 3.1, 3.2 ] ]; // 3rd row
ten = [ [ [ 111, num, 113 ] // 1st matrix, first row
, [ 121, 122, 123 ] ] // second row
, [ [ 211, 212, 213 ] // 2nd matrix, first row
, [ 221, 222, num ] ] // second row
, [ [ 311, 312, 313 ] // 3rd matrix, first row
, [ 321, num, 323 ] ] // second row
, [ [ num, 412, 413 ] // 4th matrix, first row
, [ 421, 422, 423 ] ] ]; // second row
Sofern die Unterelemente (Zeilen einer Matrix, Matrizen eines Tensors) jeweils die selbe Größe haben, wird die Größe der Struktur nur durch die Anzahl der Elemente und Unterelemente bestimmt. Im Beispiel hat vec
5 Elemente (je nach Verwendung in Zeilen oder Spalten), mat
3 Zeilen und 2 Spalten und ten
4 Matrix-Scheiben mit je 2 Zeilen und 3 Spalten. Größenunterschiede werden bei der Übersetzung als Fehler gemeldet, es findet kein automatisches Auffüllen (padding) statt.
Zugriff auf einzelne Elemente
Ein Element eines Vektors, einer Matrix oder Tensors wird ebenfalls über die [ ... ]
Syntax adressiert, wobei die Indices - wie in Programmiersprachen üblich - immer ab 0 zählen. Indices können auch aus Variablen oder Berechnungen stammen.
v_num = vec[3]; // liest das 4. Element des Vektors
m_num = mat[0, 1]; // liest in der 1. Zeile das 2. Element
t_422 = ten[3, 1, 1]; // liest aus der 4. Matrix, 2. Zeile, 2. Spalte
Triviale Operationen auf mehrdimensionalen Objekten
Folgende Operationen sind unmittelbar in der gewöhlichen Formelschreibweise implementiert:
-
Der Vergleich
==
und!=
ist auf mehrdimensionalen Objekten möglich, sofern beide Operanden die gleiche Größe besitzen. -
Addition und Subtraktion von mehrdimensionalen Objekten ist möglich, sofern beide Operanden die gleiche Größe besitzen.
M_Sum = M_1 + M_2;
M_Dif = M_1 - M_2; -
Multiplikation eines mehrdimensionalen Objekts mit einem numerischen Skalar. Das Ergebnis ist ein gleichdimensioniertes Objekt, bei dem jedes einzelne Element entsprechend skaliert ist. Das Kommutativ-Gesetz ist anwendbar.
M_Scaled_0 = M_Base * 2.56;
M_Scaled_1 = 2.56 * M_Base;- Division eins mehrdimensionalen Objekts durch einen numerischen Skalar. Das Ergebnis ist ein gleichdimensioniertes Objekt, bei dem jedes einzelne Element entsprechend skaliert ist. Die Division durch eine Matrix oder einen Vektor ist nicht zulässig.
M_Scaled_2 = M_Base / 2.56;
-
Multiplikation zweier mehrdimensionaler Objekte ist möglich, sofern die Anzahl der Spalten des ersten mit der Anzahl der Zeilen im zweiten Operanden übereinstimmt. Das Ergebnis ist ein mehrdimensionales Objekt mit der Zeilenzahl des ersten und der Spaltenzahl des zweiten Operanden. Ein Vektor unterscheidet hier nicht nach Zeilen und Spalten, sodass er als erster Operand als Zeilen-Vektor und als zweiter Operand als Spalten-Vektor interpretiert wird. Dies deckt bestimmt 95% der typischen Interpretation in technischen Anwendungen ab, ohne mit einer Transpose-Funktion arbeiten zu müssen.
M_mult = M_1 * M_2;
V_row = V_1 * M; // V_1 interpreted as row-vector
V_col = M * V_2; // v_2 interpreted as column-vector
ScalarProduct = V_1 * V_2; // by definition
CrossProduct = Cross(V_1, V_2); // := V_1 x V_2
Zuweisung eines Vektors, einer Matrix, oder eines Tensors
Eine Variable darf grundsätzlich nur an einer einzigen Stelle im Formelsatz beschrieben bzw. erzeugt werden. Dies gilt entsprechend auch für Vektoren, Matrizen und Tensoren.
Allerdings gibt es hier noch die Möglichkeit, in dieser Zuweisung indirekt einzelne Elemente der Struktur zu beschreiben. In diesem Fall muss der indizierte Zugriff auf ein Element im Formeltext nach der eigentlichen Zuweisung der Struktur erfolgen, damit der Compiler die Zuweisung des Elements in die Zuweisung der gesamten Struktur einpflegen kann.
Zirkuläre Referenzen sind hier nicht zulässig.
M_spare = Matrix(3, 3); // erzeugt zunächst eine 3x3 Matrix mit 0
M_spare[0,1] = 101; // ergänzt die erste Zuweisung für Element [0,1]
M_spare[1,2] = 202; // ergänzt die erste Zuweisung für Element [1,2]
M_spare[2,0] = 303; // ergänzt die erste Zuweisung für Element [2,0]
Wann immer die Matrix M_spare
verwendet wird, hat sie nun folgenden Inhalt:
Diese Schreibweise verbessert insbesondere für dünn besetzte Matrizen oder Vektoren die Lesbarkeit des Formeltextes.
u_long = Vector(50, 3.14); // create a very long vector
u_long[ 3] = -3.14;
u_long[25] = -3.14;
u_long[44] = u_long[10] + u_long[11]; // not allowed !!!
Für die zeitliche Fortschreibung des Vektors sind alle Datenquellen gleichberechtigt. Der Wert des gesamten Vektors ändert sich also immer dann, wenn sich mindestens ein Element ändert. Einen "Zwischenstand", bei dem die Zuweisung der Elemente noch nicht oder nur teilweise erfolgt ist, gibt es nicht.
Export von Teilen eines mehrdimensionalen Objekts
Um aus einem mehrdimensionalen Objekt einen bestimmten Teile zu extrahieren, können die Funktionen GetCol()
, GetRow()
oder GetSlice()
verwendet werden.
So kann aus einer Matrix eine bestimmte Zeile oder Spalte exportiert oder aus einem Tensor mit mehreren Matrix-Scheiben eine einzelne Matrix. GetSub()
erlaubt einen beliebigen Export eines Bereichs, der in jeder Dimension durch einen Bereich der Zeilen/Spalten/Slice-Indices definiert ist.
Funktionen
Vektorkonstruktion "Vector"
Die folgenden Funktionen können zur Konstruktion eines Vektors verwendet werden
u = Vector(size); // Mit 0 initialisierter Vektor der Dimension size x 1
u = Vector(size, v); // Mit v initialisierter Vektor der Dimension size x 1
Die Orientierung des Vektors als Zeilen- oder Spaltenvektor ist nicht festgelegt und wird in der jeweiligen Verwendung bestmöglich interpretiert.
Einheitsvektor "Normalize"
Mit der Funktion Normalize()
wird ein Einheitsvektor für den gegebenen Vektor bestimmt.
Falls der Betrag des Vektors Null ist, wir entweder ein Null-Vektor oder der Ersatzwert zurück gegeben, damit nachfolgende Berechnungsschritte nicht blockiert werden.
ev1 = Normalize(v);
ev2 = Normalize(v, v0);
Matrixkonstruktion "Matrix"
Die folgenden Funktionen können zur Konstruktion einer Matrix verwendet werden
A = Matrix(rows, columns); // Mit 0 initialisierte Matrix der Dimensionen rows x columns
B = Matrix(rows, columns, v); // Mit v initialisierte Matrix der Dimensionen rows x columns
Identitätsmatrix "MIdent"
Folgende Funktion liefert eine Identitätsmatrix der Dimensionen size x size
I = MIdent(size);
Rotationsmatrix "MRot"
Es ist möglich, Rotationsmatrizen folgender Art zu definieren
R_2 = MRot(alpha); // 2D-Rotationsmatrix um den Winkel alpha gegen den Uhrzeigersinn
R_3 = MRot(alpha, axis); // 3D-Rotationsmatrix um die mit axis bezeichnete Achse: x:0, y:1, z:2
M_3ypr = MRotYPR(y,p,r); // 3D-Rotationsmatrix, die eine durch Yaw, Pitch und Roll
// beschriebene Rotation beschreibt
M_3euler = MRotEuler(a,b,g); // 3D-Rotationsmatrix, die eine durch a, b, g beschriebene
// Euler-Rotation beschreibt
Mit
-
und
-
ist
Siehe dazu auch: Drehmatrix – Wikipedia
Mit
- , (Yaw),
- , (Gear) und
- , (Roll) ist
Siehe dazu auch: Eulersche – Winkel
Mit
- , (input Z-axis),
- , (node line, rotated X-axis) und
- , (output Z-axis) ist
Siehe dazu auch: Eulersche – Winkel
Tensorkonstruktion "Tensor"
Zur Konstruktion eines Tensors mit slices Scheiben der Dimension rows x columns verwendet man
T = Tensor(slices, rows, columns);
Eigenschaften von Vektoren, Matrizen, Tensoren
Überprüfung auf den Typ einer Variable "isScalar", "isVector", "isMatrix", "isTensor"
Die folgenden Funktionen liefern jeweils ein true, wenn die Variable die abgefragte Struktur besitzt. Dies kann sinnvoll sein, wenn eine Funktion, z.B: sFind()
sowohl einen Skalar (-1, nicht gefunden) oder eine Matrix mit Ergebnissen zurück liefert und die weitere Verarbeitung davon abhängig ist.
test1 = isScalar(var);
test2 = isVector(var);
test3 = isMatrix(var);
test4 = isTensor(var);
Abfrage der Dimensionen eines Objekts "SizeOf"
Die Abfrage der Dimensionen eines Objekts liefert einen Vektor der Dimensionen zurück, z.B.
VectorSize = SizeOf(v); // => [ 1, size ]
MatrixSize = SizeOf(M); // => [ 2, columns, rows]
TensorSize = SizeOf(T); // => [ 3, columns, rows, slices ]
Darin liefert die erste Komponenten die Anzahl der Dimensionen und die folgenden die Anzahl der Elemente in der jeweiligen Dimension.
Zugriffsfunktionen "GetCol", "GetRow", "GetSlice", "GetSub"
Diese Funktionen dienen dazu, Teile aus einem mehrdimensionalen Objekt herauszuschneiden, sodass in der Regel wieder ein mehrdimensionales Objekt entsteht. Für den Zugriff auf ein einzzelnes Element sollte effektiver die Index-Syntax verwendet werden.
Der Schnitt durch ein mehrdimensionales Objekt an einem bezeichneten Spaltenindex columnIndex kann wie folgt durchgeführt werden
v1 = GetCol(D, columnIndex);
v2 = GetCol(D, {...}); // Konfiguration verpflichtend!
// Konfiguration für alle Varianten
vx = GetCol(..., { col: <uint> // verpflichtend, falls kein columnIndex
, rBeg: <uint>
, rEnd: <uint>
, sBeg: <uint>
, sEnd: <uint>
});
Für einen Vektor ist das Ergebnis ein einzelnes Element, für eine Matrix ein Vektor und für einen Tensor eine Matrix am bezeichneten Spaltenindex. Dabei können für Strukturen höherer Ordnung die kopierten Bereiche über das Konfigurationsobjekt ebenfalls eingeschränkt werden.
Eigenschaft | Wert | Beschreibung |
---|---|---|
col | <uint> | Spaltenindex für die Schnittebene |
rBeg | <uint> | Optionale Bereichsangabe für Zeilen |
rEnd | <uint> | Optionale Bereichsangabe für Zeilen |
sBeg | <uint> | Optionale Bereichsangabe für Scheiben |
sEnd | <uint> | Optionale Bereichsangabe für Scheiben |
Der Schnitt durch ein mehrdimensionales Objekt an einem bezeichneten Zeilenindex kann wie folgt durchgeführt werden
v1 = GetRow(D, rowIndex);
v2 = GetRow(D, {...}); // Konfiguration verpflichtend!
// Konfiguration für alle Varianten
vx = GetRow(..., { cBeg: <uint>
, cEnd: <uint>
, row: <uint> // verpflichtend, falls kein rowIndex
, sBeg: <uint>
, sEnd: <uint>
});
Für einen Vektor ist das Ergebnis ein einzelnes Element, für eine Matrix ein Vektor und für einen Tensor eine Matrix am bezeichneten Zeilenindex. Dabei können für Strukturen höherer Ordnung die kopierten Bereiche über das Konfigurationsobjekt ebenfalls eingeschränkt werden.
Eigenschaft | Wert | Beschreibung |
---|---|---|
row | <uint> | Zeilenindex für die Schnittebene |
cBeg | <uint> | Optionale Bereichsangabe für Spalten |
cEnd | <uint> | Optionale Bereichsangabe für Spalten |
sBeg | <uint> | Optionale Bereichsangabe für Scheiben |
sEnd | <uint> | Optionale Bereichsangabe für Scheiben |
Der Schnitt durch ein mehrdimensionales Objekt an einem bezeichneten Scheibenindex kann wie folgt durchgeführt werden
v1 = GetSlice(D, sliceIndex);
v2 = GetSlice(D, {...}); // Konfiguration verpflichtend!
// Konfiguration für alle Varianten
vx = GetSlice(..., { cBeg: <uint>
, cEnd: <uint>
, rBeg: <uint>
, rEnd: <uint>
, slice:<uint> // verpflichtend, falls kein sliceIndex
});
Für einen Vektor ist das Ergebnis ein einzelnes Element, für eine Matrix ein Vektor und für einen Tensor eine Matrix am bezeichneten Scheibenindex. Dabei können für Strukturen höherer Ordnung die kopierten Bereiche über das Konfigurationsobjekt ebenfalls eingeschränkt werden.
Eigenschaft | Wert | Beschreibung |
---|---|---|
slice | <uint> | Scheibenindex für die Schnittebene |
cBeg | <uint> | Optionale Bereichsangabe für Spalten |
cEnd | <uint> | Optionale Bereichsangabe für Spalten |
rBeg | <uint> | Optionale Bereichsangabe für Zeilen |
rEnd | <uint> | Optionale Bereichsangabe für Zeilen |
Die Extraktion einer Unterstruktur von Daten aus einer Struktur von Daten erfolgt wie folgt
D1 = GetSub(D, { cBeg: <uint>
, cEnd: <uint>
, rBeg: <uint>
, rEnd: <uint>
, sBeg: <uint>
, sEnd: <uint>
});
Eigenschaft | Wert | Beschreibung |
---|---|---|
cBeg | <uint> | Optionale Bereichsangabe für Spalten |
cEnd | <uint> | Optionale Bereichsangabe für Spalten |
rBeg | <uint> | Optionale Bereichsangabe für Zeilen |
rEnd | <uint> | Optionale Bereichsangabe für Zeilen |
sBeg | <uint> | Optionale Bereichsangabe für Scheiben |
sEnd | <uint> | Optionale Bereichsangabe für Scheiben |
Verarbeitende Funktionen
Transposition "Trans"
Die Transposition einer M x N Matrix liefert eine N x M Matrix zurück, wobei Zeilen und Spalten vertauscht sind und wird wie folgt berechnet
A_t = Trans(A);
Kreuzprodukt "Cross"
Das Kreuzprodukt zweier Vektoren u und v der Länge 2 oder 3 liefert einen hierzu senkrechten Vektor in der Länge der durch beide Vektoren aufgespannten Fläche und wird berechnet wie folgt
w = Cross(u, v);
LU Dekomposition "LUDecomp"
Die LU Dekomposition einer Matrix M liefert eine untere Dreiecksmatrix L sowie eine obere Dreiecksmatrix U in Form eines Tensors mit zwei Scheiben zurück und kann wie folgt durchgeführt werden
T = LUDecomp(M);
L = GetSlice(T, 0);
U = GetSlice(T, 1);
Determinante "Det"
Die Determinante d einer quadratischen Matrix M kann wie folgt berechnet werden
d = Det(M);
Vektorlänge "Length"
Berechnung der Länge eines Vektors, sie auch abs(...)
len = Length(v);