Zum Hauptinhalt springen

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:

MSpare=[010100020230300]M_{\rm{Spare}} = \left[ \begin{array}{ccc} 0&101&0\\ 0&0&202\\ 303&0&0 \end{array} \right]

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.

e=vv\vec{e}=\frac{\vec{v}}{||\vec{v}||}

Falls der Betrag des Vektors Null ist, wir entweder ein Null-Vektor oder der Ersatzwert v0\vec{v}_0 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);
I=[100010001]I = \left[ {\begin{array}{cccc} 1&0& \cdots &0\\ 0&1& \ddots & \vdots \\ \vdots & \ddots & \ddots &0\\ 0& \cdots &0&1 \end{array}} \right]

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

  • cα=cos(α)c\alpha = cos(\alpha) und

  • sα=sin(α)s\alpha = sin(\alpha) ist

MRot(α)=[cαsαsαcα]MRot(\alpha) = \left[ {\begin{array}{cc} c\alpha & -s\alpha\\ s\alpha & c\alpha \end{array}} \right] MRot(α,0)=[1.00.00.00.0cαsα0.0sαcα]MRot(\alpha, 0) = \left[ {\begin{array}{ccc} 1.0 & 0.0 & 0.0 \\ 0.0 & c\alpha & -s\alpha\\ 0.0 & s\alpha & c\alpha \end{array}} \right] MRot(α,1)=[cα0.0sα0.01.00.0sα0.0cα]MRot(\alpha, 1) = \left[ {\begin{array}{ccc} c\alpha & 0.0 & s\alpha \\ 0.0 & 1.0 & 0.0\\ -s\alpha & 0.0 & c\alpha \end{array}} \right] MRot(α,2)=[cαsα0.0sαcα0.00.00.01.0]MRot(\alpha, 2) = \left[ {\begin{array}{ccc} c\alpha & -s\alpha & 0.0 \\ s\alpha & c\alpha & 0.0\\ 0.0 & 0.0 & 1.0 \end{array}} \right]

Siehe dazu auch: Drehmatrix – Wikipedia

Mit

  • cψ=cos(ψ)c\psi=cos(\psi), sψ=sin(ψ)s\psi=sin(\psi) (Yaw),
  • cθ=cos(θ)c\theta=cos(\theta), sθ=sin(θ)s\theta=sin(\theta) (Gear) und
  • cϕ=cos(ϕ)c\phi=cos(\phi), sϕ=sin(ϕ)s\phi=sin(\phi) (Roll) ist
MRotYPR(ψ,θ,ϕ)=[cθcψsϕsθcψcϕsψcϕsθcψ+sϕsψcθsψsϕsθsψ+cϕcψcϕsθsψsϕcψsθsϕcθcϕcθ]\rm{MRotYPR}(\psi,\theta,\phi) = \left[ {\begin{array}{ccc} c\theta \cdot c\psi & s\phi \cdot s\theta \cdot c\psi - c\phi \cdot s\psi & c\phi \cdot s\theta \cdot c\psi + s\phi \cdot s\psi \\ c\theta \cdot s\psi & s\phi \cdot s\theta \cdot s\psi + c\phi \cdot c\psi & c\phi \cdot s\theta \cdot s\psi - s\phi \cdot c\psi \\ - s\theta & s\phi \cdot c\theta & c\phi \cdot c\theta \end{array}} \right]

Siehe dazu auch: Eulersche – Winkel

Mit

  • cα=cos(α)c\alpha=cos(\alpha), sα=sin(α)s\alpha=sin(\alpha) (input Z-axis),
  • cβ=cos(β)c\beta=cos(\beta), sβ=sin(β)s\beta=sin(\beta) (node line, rotated X-axis) und
  • cγ=cos(γ)c\gamma=cos(\gamma), sγ=sin(γ)s\gamma=sin(\gamma) (output Z-axis) ist
MRotEuler(α,β,γ)=[cαcγsαcβsγcαsγsαcβcγsαsβsαcγ+cαcβsγsαsγ+cαcβcγcαsβsβsγsβcγcβ]\rm{MRotEuler}(\alpha,\beta,\gamma) = \left[ {\begin{array}{ccc} c\alpha \cdot c\gamma - s\alpha \cdot c\beta \cdot s\gamma& - c\alpha \cdot s\gamma - s\alpha \cdot c\beta \cdot c\gamma& s\alpha \cdot s\beta \\ s\alpha \cdot c\gamma + c\alpha \cdot c\beta \cdot s\gamma& - s\alpha \cdot s\gamma + c\alpha \cdot c\beta \cdot c\gamma& - c\alpha \cdot s\beta \\ s\beta \cdot s\gamma & s\beta \cdot c\gamma & c\beta \end{array}} \right]

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"

tipp

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.

EigenschaftWertBeschreibung
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.

EigenschaftWertBeschreibung
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.

EigenschaftWertBeschreibung
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>
});
EigenschaftWertBeschreibung
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);
A=[a11a12a1NaM1aM2aMN],AT=[a11aM1a12aM2a1NaMN]A = \left[\begin{array}{cccc} {{a_{11}}}&{{a_{12}}}& \cdots &{{a_{1N}}}\\ \vdots & \ddots & \ddots & \vdots \\ {{a_{M1}}}&{{a_{M2}}}& \cdots &{{a_{MN}}} \end{array}\right],A^T = \left[ \begin{array}{ccc} {{a_{11}}}& \cdots &{{a_{M1}}}\\ {{a_{12}}}& \ddots &{{a_{M2}}}\\ \vdots & \ddots & \vdots \\ {{a_{1N}}}& \cdots &{{a_{MN}}} \end{array}\right]

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);
w=[uxuyuz]×[vxvyvz]=[uyvzuzvyuzvxuxvzuxvyuyvx]\vec{w}=\left[ {\begin{array}{c} {{u_x}}\\ {{u_y}}\\ {{u_z}} \end{array}} \right] \times \left[ {\begin{array}{c} {{v_x}}\\ {{v_y}}\\ {{v_z}} \end{array}} \right] = \left[ {\begin{array}{c} {{u_y}{v_z} - {u_z}{v_y}}\\ {{u_z}{v_x} - {u_x}{v_z}}\\ {{u_x}{v_y} - {u_y}{v_x}} \end{array}} \right]

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);
len=v02+v12+...+vn12len = \sqrt{v_0^2 + v_1^2 + ... + v_{n-1}^2}