CasADi – Ausführliche Erläuterung der Datentypen und Einführung in grundlegende Operationen


1. Häufig verwendete Symbole

1.1 SX-Symbol

  Der Datentyp SX wird zur Darstellung von Matrizen verwendet, deren Elemente aus symbolischen Ausdrücken bestehen, die aus einer Folge unärer und binärer Operationen bestehen. Um zu sehen, wie das in der Praxis funktioniert, starten Sie eine interaktive Python-Shell (z. B. durch Eingabe von ipython von einem Linux-Terminal oder in einer integrierten Entwicklungsumgebung wie Spyder) oder starten Sie die grafische Benutzeroberfläche von MATLAB oder Octave. Vorausgesetzt, CasADi ist korrekt installiert, können Sie die Bibliothek wie folgt in Ihren Arbeitsbereich importieren:

from casadi import *

Erstellen Sie eine Variable x mit der folgenden Syntax:

x = MX.sym("x")
print(x)

Die Ausgabe nach dem Ausführen ist:

X

Der obige Code erstellt eine 1×1-Matrix, bei der es sich um ein symbolisches Grundelement mit dem Namen x handelt (das ein Skalar ist). Dies ist nur ein Anzeigename, keine Kennung. Mehrere Variablen können denselben Namen haben und dennoch unterschiedlich sein. Der Bezeichner ist der Rückgabewert. Zusätzlich kann die Funktion SX.sym (mit Parametern) aufgerufen werden, um symbolische Variablen mit Vektor- oder Matrixwert zu erstellen:

y = SX.sym('y',5)
Z = SX.sym('Z',4,2)
print(y)
print(z)

Die Ausgabe nach dem Ausführen ist:

[y_0, y_1, y_2, y_3, y_4]
[[Z_0, Z_4],
 [Z_1, Z_5],
 [Z_2, Z_6],
 [Z_3, Z_7]]

Der obige Code erstellt eine 5×1-Matrix (d. h. einen Vektor) bzw. eine 4×2-Matrix mit symbolischen Grundelementen. SX.sym ist eine (statische) Funktion, die eine SX-Instanz zurückgibt. Nach der Deklaration einer Variablen können nun Ausdrücke auf intuitive Weise gebildet werden:

f = x**2 + 10
f = sqrt(f)
print(f)

Die Ausgabe nach dem Ausführen ist:

sqrt((10+sq(x)))

Darüber hinaus ist es möglich, SX-Instanzen ohne Konstanten zu erstellen:

B1 = SX.zeros(4,5): # 一个全零的密集 4×5 空矩阵 
B2 = SX(4,5): # 全零的稀疏 4×5 空矩阵 
B4 = SX.eye(4): # 稀疏的4×4矩阵,对角线为1 
print(B1)
print(B2)
print(B4)

Die Ausgabe nach dem Ausführen ist:

B1: @1=0,
[[@1, @1, @1, @1, @1],
 [@1, @1, @1, @1, @1],
 [@1, @1, @ 1, @1, @1],
 [@1, @1, @1, @1, @1]]
B2:
[[00, 00, 00, 00, 00],
 [00, 00, 00, 00, 00],
 [00, 00, 00, 00, 00],
 [00, 00, 00, 00, 00]]
B4: @1=1,
[[@1, 00, 00, 00],
 [00, @ 1, 00, 00],
 [00, 00, @1, 00],
 [00, 00, 00, @1]]

  Hinweis : Beachten Sie den Unterschied zwischen den obigen Ausdrücken: Wenn Sie einen Ausdruck mit strukturellen Nullen drucken (Elemente in einer spärlichen Matrix, die nicht explizit zugewiesen sind), werden diese Nullen als 00 dargestellt, um sie mit tatsächlichen Nullen @1 (tatsächlich explizit für Elemente) zu vergleichen Durch die Formel zugewiesen, verwenden Sie @1, um nach dem Drucken 0 darzustellen, um den Unterschied zwischen strukturellem Null und tatsächlichem Null zu unterscheiden.

Zusätzlich zu den oben genannten Verwendungsmethoden sind in der folgenden Tabelle häufig verwendete SX-Ausdrücke aufgeführt:

Funktionsausdruck verwenden
SX.sym(name,n,m) Erstellen Sie ein n×m symbolisches Grundelement
SX.zeros(n,m) Erstellen Sie eine n-mal-m-dichte Matrix mit allen Nullelementen
SX(n,m) Erstellen Sie eine n×m-sparse-Matrix mit allen Nullelementen
SX.ones(n,m) Erstellen Sie eine N-mal-M-dichte Matrix, die nur Einsen enthält
SX.eye(n) Erstellen Sie eine n×n-Diagonalmatrix mit 1 Elementen auf der Diagonale und strukturellen Nullstellen an anderer Stelle.
SX(scalar_type) Erstellt einen Skalar (1×1-Matrix) unter Verwendung der durch die Argumente angegebenen Werte. Diese Methode kann explizit verwendet werden, z. B. SX(9), oder implizit, z. B. 9 * SX.ones(2,2)
SX(matrix_type) Erstellt eine Matrix der angegebenen numerischen Matrix, entweder als NumPy- oder SciPy-Matrix (in Python) oder als dichte oder dünn besetzte Matrix (in MATLAB/Octave). In MATLAB/Octave stellt beispielsweise SX([1,2,3,4]) einen Zeilenvektor dar, SX([1;2;3;4]) stellt einen Spaltenvektor dar, SX([1,2;3 ,4]) stellt eine 2×2-Matrix dar und diese Methode kann explizit oder implizit verwendet werden.
repmat(v,n,m) Wiederholen Sie den Ausdruck v n-mal in vertikaler Richtung und m-mal in horizontaler Richtung. Beispiel: repmat(SX(3),2,1) erstellt eine 2×1-Matrix, bei der alle Elemente 3 sind.
SX(list) (nur Python) Erstellen Sie einen Spaltenvektor (n-mal-1-Matrix) mithilfe der Elemente in der Liste, z. B. SX([1,2,3,4]). (Beachten Sie den Unterschied zwischen Python-Listen und der horizontalen Verkettung von MATLAB/Octave. Beide verwenden die Syntax mit eckigen Klammern.)
SX (Liste der Liste) (nur Python) Erstellen Sie eine dichte Matrix mit den Elementen in der Liste, zum Beispiel SX([[1,2],[3,4]]) oder erstellen Sie eine (1×n-Matrix mit SX([[1,2,3,4] ]) ) Zeilenvektor.

1.2 DM-Symbole

  DM ist SX sehr ähnlich, außer dass die Elemente ungleich Null numerische Werte und keine symbolischen Ausdrücke sind. Die DM-Syntax ist mit Ausnahme einiger Funktionen wie SX.sym ebenfalls dieselbe wie die von SX.

  DM wird hauptsächlich zum Speichern von Matrizen in CasADi und als Ein- und Ausgabe von Funktionen verwendet. Es ist nicht für rechenintensive Berechnungen vorgesehen. Verwenden Sie dazu die integrierten dichten oder spärlichen Datentypen in MATLAB, NumPy- oder SciPy-Matrizen in Python oder eine auf Ausdrucksvorlagen basierende Bibliothek wie Eigen, Ublas oder MTL in C++. Die Konvertierung zwischen Typen ist normalerweise einfach:

C = DM(2,3)

C_dense = C.full()
from numpy import array
C_dense = array(C) # equivalent

C_sparse = C.sparse()
from scipy.sparse import csc_matrix
C_sparse = csc_matrix(C) # equivalent

  Weitere Beispiele für die Verwendung von SX finden Sie im Beispielpaket unter http://install.casadi.org/. Dokumentation zu bestimmten Funktionen dieser Klasse (und anderer Klassen), wie z. B. der C++-API, finden Sie unter http://docs.casadi.org/.


1.3 MX-Notation

  Die Ausgabe des folgenden Codes ist eine 2×2-Matrix. Achten Sie hier auf den ersten Satz @1=3, was bedeutet, dass @1 in der Ausgabe der zweiten Zeile 3 darstellt . Das Ausgabeergebnis bedeutet, dass CasADi jeweils ist Matrix f Der Eintrag erstellt einen neuen Ausdruck (Typ SX).

x = SX.sym('x',2,2)
y = SX.sym('y')
f = 3*x + y
print(f)
print(f.shape)

Die Ausgabe nach dem Ausführen ist:

@1=3,
[[((@1 x_0)+y), ((@1 x_2)+y)],
 [((@1 x_1)+y), ((@1 x_3)+y)]]
(2, 2)

  Zusätzlich zu der oben genannten Methode können wir auch den zweiten, allgemeineren Matrixausdruckstyp MX verwenden. Der MX-Typ ermöglicht die Konstruktion von Ausdrücken, die genau wie SX aus einer Reihe grundlegender Operationen bestehen. Aber im Gegensatz zu SX sind diese Grundoperationen nicht auf skalare unäre oder binäre Operationen beschränkt ( R → R \mathbb{R}→\mathbb{R}RRR × R → R\mathbb{R}×\mathbb{R}→\mathbb{R}R×RR ). Stattdessen können die Grundoperationen zum Bilden von MX-Ausdrücken allgemeine Eingaben mehrerer Sparse-Matrixwerte und Ausgabefunktionen mehrerer Sparse-Matrixwerte sein:R n 1 × m 1 × … × R n N × m N → R p 1 × q 1 × … × R p M × q M \mathbb{R}^{ { n_1}×{m_1}}×…×\mathbb{R}^{ { n_N}×{m_N}}→\mathbb{ R}^{ {p_1 }×{q_1}}×…×\mathbb{R}^{ {p_M}×{q_M}}RN1× m1××RNN× mNRP1× q1××RPM× qM,Zum Beispiel:

x = MX.sym('x',2,2)
y = MX.sym('y')
f = 3*x + y
print(f)
print(f.shape)

Die Ausgabe nach dem Ausführen ist:

((3*x)+y)
(2, 2)

  Die beiden oben genannten Codeteile haben das gleiche Ergebnis, die MX-Notation besteht nur aus zwei Operationen (einer Multiplikation und einer Addition), während das SX-Äquivalent acht hat (jedes Element besteht aus zwei, f(1,1) besteht aus (@) 1x_0) und y-Zusammensetzung). Daher kann MX wirtschaftlicher sein, wenn Operationen mit natürlichen Vektor- oder Matrixwerten mit vielen Elementen verwendet werden.

  MX unterstützt das Abrufen und Festlegen von Elementen mit derselben Syntax wie SX, die Implementierung ist jedoch sehr unterschiedlich. Testen Sie beispielsweise das Drucken des oberen linken Elements einer symbolischen 2×2-Variablen:

x = MX.sym('x',2,2)
print(x[0,0])

Die Ausgabe sollte als Ausdruck verstanden werden, der dem ersten (d. h. Index 0 in C++) strukturell ungleich Null-Element von x entspricht, das die erste (Index 0) Position der Matrix ist, im Gegensatz zu x_0 im SX-Fall oben.

  Beim Festlegen von Elementen ist die Verwendung ähnlich:

x = MX.sym('x',2)
A = MX(2,2)
A[0,0] = x[0]
A[1,1] = x[0]+x[1]
print('A:', A)

Die Ausgabe nach dem Ausführen ist:

A: (Projekt((nullen(2x2,1nz)[0] = x[0]))[1] = (x[0]+x[1]))

Diese Ausgabe kann wie folgt verstanden werden: Ausgehend von einer All-Null-Sparse-Matrix wird x_0 ein Element zugewiesen. Projizieren Sie es dann auf eine Matrix unterschiedlicher Sparsität und weisen Sie x_0+x_1 ein weiteres Element zu.


1.4 Mischung aus SX und MX

  Sie können SX-Objekte nicht mit MX-Objekten multiplizieren oder andere Operationen ausführen, um die beiden im selben Ausdrucksdiagramm zu mischen. Es ist jedoch möglich, Aufrufe von durch SX-Ausdrücke definierten Funktionen in das MX-Diagramm aufzunehmen. Wenn Sie die Effizienz Ihres Programms verbessern müssen, können Sie SX und MX kombinieren, da der Overhead jeder Operation von durch SX-Ausdrücke definierten Funktionen viel geringer ist, wodurch das System eine Reihe skalarer Operationen schneller abschließen kann. Daher sind SX-Ausdrücke für Operationen auf niedriger Ebene gedacht, während MX-Ausdrücke zur Implementierung verantwortungsvoller Operationen verwendet werden, beispielsweise zur Implementierung von Einschränkungsfunktionen für NLP.


1,5 Sparse-Klasse

  Matrizen in CasADi werden im CCS-Format (Compressed Column Storage) gespeichert. Dies ist ein Standardformat für dünn besetzte Matrizen, das eine effiziente Durchführung linearer Algebraoperationen wie elementweiser Operationen, Matrixmultiplikationen und Transponierungen ermöglicht. Im CCS-Format verwendet der Sparse-Modus Dimensionen (Anzahl der Zeilen und Spalten) und zwei Vektoren zur Dekodierung. Der erste Vektor enthält den Index des ersten strukturell von Null verschiedenen Elements jeder Spalte, und der zweite Vektor enthält den Zeilenindex jedes von Null verschiedenen Elements. Weitere Details zum CCS-Format finden Sie beispielsweise in der Vorlage für lineare Systemlösungen auf Netlib. Beachten Sie, dass CasADi das CCS-Format für dünn besetzte und dichte Matrizen verwendet.

  Sparsity-Muster in CasADi werden als Instanzen der Sparsity-Klasse gespeichert, die referenzzählbar ist. Dies bedeutet, dass mehrere Matrizen dasselbe Sparsity-Muster verwenden können, einschließlich MX-Ausdrucksdiagrammen und Instanzen von SX und DM. Sparse-Klassen werden ebenfalls zwischengespeichert, was bedeutet, dass die Erstellung mehrerer Instanzen desselben Sparse-Musters immer vermieden wird.

  Die folgende Liste fasst die gängigsten Methoden zum Erstellen neuer Sparse-Muster zusammen:

Funktionsname Funktion
Sparsity.dense(n,m) Erstellen Sie ein dichtes n×m-Muster mit geringer Dichte
Sparsity(n,m) Erstellen Sie ein spärliches n×m-Sparse-Muster
Sparsity.diag(n) Erstellen Sie ein diagonales n×n-sparse-Muster
Sparsity.upper(n) Erstellen Sie ein oberes dreieckiges n×n-Sparse-Muster
Sparsity.lower(n) Erstellen Sie ein unteres dreieckiges n×n-Sparse-Muster

  Sparse-Klassen können zum Erstellen nicht standardmäßiger Matrizen verwendet werden, zum Beispiel:

print(SX.sym('x',Sparsity.lower(3)))

Die Ausgabe nach dem Ausführen ist:

[[x_0, 00, 00],
 [x_1, x_3, 00],
 [x_2, x_4, x_5]]

1.5.1 Elemente in einer Matrix abrufen und festlegen

  Um ein Element oder einen Satz von Elementen in CasADi-Matrixtypen (SX, MX und DM) abzurufen oder festzulegen, verwenden wir eckige Klammern in Python und runde Klammern in C++ und MATLAB. Gemäß der Konvention dieser Sprachen beginnt die Indizierung in C++ und Python bei 0 und in MATLAB bei 1. In Python und C++ erlauben wir negative Indizes, um Indizes anzugeben, die vom Ende an zählen. Verwenden Sie in MATLAB das Schlüsselwort end, um die Indizierung am Ende zu starten.

  Die Indizierung kann mit einem Index oder zwei Indizes erfolgen. Mithilfe von zwei Indizes können Sie auf eine bestimmte Zeile (oder eine oder mehrere Zeilengruppen) und eine bestimmte Spalte (oder eine Spaltengruppe) zugreifen. Mit einem Index können Sie auf ein Element (oder eine Gruppe von Elementen) zugreifen, beginnend in der oberen linken Ecke und spaltenweise bis zur unteren rechten Ecke. Es werden alle Elemente gezählt, unabhängig davon, ob sie strukturell Null sind. Zum Beispiel:

M = SX([[3,7],[4,5]])
print(M[0,:])
M[0,:] = 1
print(M)

Die Ausgabe nach dem Ausführen ist:

[[3, 7]]
@1=1,
[[@1, @1],
 [4, 5]]

  Im Gegensatz zu Pythons NumPy sind CasADi-Slices keine Ansichten der Daten auf der linken Seite; stattdessen kopiert der Slice-Zugriff die Daten. Daher hat sich im folgenden Beispiel die Matrix m überhaupt nicht geändert:

M = SX([[3,7],[4,5]])
M[0,:][0,0] = 1
print(M)

Die Ausgabe nach dem Ausführen ist:

[[3, 7],
 [4, 5]]

  Das Abrufen und Festlegen von Matrixelementen wird im Folgenden detailliert beschrieben. Diese Diskussion gilt für alle Matrixtypen von CasADi.

  Erhalten oder legen Sie den Einzelelementzugriff fest, indem Sie ein Zeilen-Spalten-Paar oder seinen abgeflachten Index bereitstellen (spaltenweise beginnend in der oberen linken Ecke der Matrix):

M = diag(SX([3,4,5,6]))
print(M)

Die Ausgabe nach dem Ausführen ist:

[[3, 00, 00, 00],
 [00, 4, 00, 00],
 [00, 00, 5, 00],

 [00, 00, 00, 6]]

print(M[0,0])
print(M[1,0])
print(M[-1,-1])

Die Ausgabe nach dem Ausführen ist:

3
00
6

  Unter Slice-Zugriff versteht man das gleichzeitige Festlegen mehrerer Elemente. Dies ist viel effizienter, als jeweils nur ein Element festzulegen. Ein Fragment kann durch die Bereitstellung eines (Start-, Stopp-, Schritt-)Tupels erhalten oder festgelegt werden. In Python und MATLAB verwendet CasADi die Standardsyntax:

print(M[:,1])
print(M[1:,1:4:2])  # 对应(start , stop , step) 

Die Ausgabe nach dem Ausführen ist:

[00, 4, 00, 00]

[[4, 00],
 [00, 00],
 [00, 6]]

  Der Listenzugriff ähnelt dem Fragmentzugriff (ist jedoch wahrscheinlich weniger effizient als dieser):

M = SX([[3,7,8,9],[4,5,6,1]])
print(M)
print(M[0,[0,3]], M[[5,-6]])

Die Ausgabe nach dem Ausführen ist:

[[3, 7, 8, 9],
 [4, 5, 6, 1]]
[[3, 9]] [6, 7]


1.6 Arithmetische Operationen

1.6.1 Multiplikation

  CasADi unterstützt die meisten Standard-Rechenoperationen wie Addition, Multiplikation, Potenzen, trigonometrische Funktionen usw.:

x = SX.sym('x')
y = SX.sym('y',2,2)
print(sin(y)-x)

Die Ausgabe nach dem Ausführen ist:

[[(sin(y_0)-x), (sin(y_2)-x)],
 [(sin(y_1)-x), (sin(y_3)-x)]]

  In C++ und Python (jedoch nicht in MATLAB) wird die Standardmultiplikationsoperation (mit *) immer noch für die elementweise Multiplikation verwendet (in MATLAB .*). Verwenden Sie für die Matrixmultiplikation A @ B oder (mtimes(A,B) in Python 3.4+):

print(y*y, y@y)

Die Ausgabe nach dem Ausführen ist:

[[sq(y_0), sq(y_2)],
 [sq(y_1), sq(y_3)]]
[[(sq(y_0)+(y_2*y_1)), ((y_0*y_2)+(y_2* y_3))],
 [((y_1*y_0)+(y_3*y_1)), ((y_1*y_2)+sq(y_3))]]

Gemäß der Konvention in MATLAB ist die Multiplikation mit * und .* äquivalent, wenn eines der Argumente ein Skalar ist.

1.6.2 transponieren

  Transpose wird mithilfe der Syntax AT in Python, AT() in C++ und A oder A gebildet. In MATLAB:

print(y)
print(y.T)

Die Ausgabe nach dem Ausführen ist:

[[y_0, y_2],
 [y_1, y_3]]

[[y_0, y_1],
 [y_2, y_3]]

1.6.3 reshape()

  Umformen bedeutet, die Anzahl der Zeilen und Spalten zu ändern, aber die Anzahl der Elemente und die relativen Positionen von Elementen ungleich Null beizubehalten. Dies ist eine sehr rechenintensive Operation und wird mit der folgenden Syntax ausgeführt:

x = SX.eye(4)
print(reshape(x,2,8))

Die Ausgabe nach dem Ausführen ist:

@1=1,
[[@1, 00, 00, 00, 00, @1, 00, 00],
 [00, 00, @1, 00, 00, 00, 00, @1]]

1.6.4 vertcat()/horzcat()

  Unter Verkettung versteht man das horizontale oder vertikale Stapeln von Matrizen. Aufgrund der spaltenorientierten Art der Elementspeicherung in CasADi sind horizontal gestapelte Matrizen am effizientesten. Matrizen, die eigentlich Spaltenvektoren sind (also aus einer einzigen Spalte bestehen), können auch effizient vertikal gestapelt werden. Führen Sie vertikale und horizontale Verknüpfungen mit den Funktionen vertcat und horzcat in Python und C++ durch (unter Verwendung einer variablen Anzahl von Eingabeargumenten) und unter Verwendung von eckigen Klammern in MATLAB:

x = SX.sym('x',5)
y = SX.sym('y',5)
print(vertcat(x,y))

Die Ausgabe nach dem Ausführen ist:

[x_0, x_1, x_2, x_3, x_4, y_0, y_1, y_2, y_3, y_4]

print(horzcat(x,y))

Die Ausgabe nach dem Ausführen ist:

[[x_0, y_0],
 [x_1, y_1],
 [x_2, y_2],
 [x_3, y_3],
 [x_4, y_4]]

  Es gibt auch Variationen dieser Funktionen, die eine Liste (in Python) oder ein Zellenarray (in Matlab) als Eingabe verwenden:

L = [x,y]
print(hcat(L))

Die Ausgabe nach dem Ausführen ist:

[[x_0, y_0],
 [x_1, y_1],
 [x_2, y_2],
 [x_3, y_3],
 [x_4, y_4]]

1.6.5 geteilt

  Horizontale und vertikale Aufteilung sind die Umkehroperationen der oben eingeführten horizontalen und vertikalen Verkettung. Um einen Ausdruck horizontal in n kleinere Ausdrücke aufzuteilen, müssen Sie zusätzlich zum aufzuteilenden Ausdruck einen Vektoroffset der Länge n+1 angeben. Das erste Element des Offset-Vektors muss 0 sein und das letzte Element muss die Spaltennummer sein. Die übrigen Elemente müssen in nicht absteigender Reihenfolge vorliegen. Dann enthält die Ausgabe i der Teilungsoperation offset[i]≤c<offset[i+1] mit offset[i]≤c<offset[i+1]o f f s e t [ i ]C<o f f s e t [ i+1 ] Spalte c. Die Syntax wird unten demonstriert:

x = SX.sym('x',5,2)
w = horzsplit(x,[0,1,2])
print(w[0], w[1])

Die Ausgabe nach dem Ausführen ist:

[x_0, x_1, x_2, x_3, x_4] [x_5, x_6, x_7, x_8, x_9]

  Die Vertsplit-Operation funktioniert ähnlich, die Offset-Vektoren beziehen sich jedoch auf Zeilen:

w = vertsplit(x,[0,3,5])
print(w[0], w[1])

Die Ausgabe nach dem Ausführen ist:

[[x_0, x_5],
 [x_1, x_6],
 [x_2, x_7]]
[[x_3, x_8],
 [x_4, x_9]]

  Für die obige vertikale Aufteilung können Sie den Fragmentzugriff anstelle der horizontalen und vertikalen Aufteilung verwenden:

w = [x[0:3,:], x[3:5,:]]
print(w[0], w[1])

Die Ausgabe nach dem Ausführen ist:

[[x_0, x_5],
 [x_1, x_6],
 [x_2, x_7]]
[[x_3, x_8],
 [x_4, x_9]]

  Für von SX erstellte Variablen ist diese Alternative völlig gleichwertig, aber für MX-Plots ist es viel effizienter, Horzsplit/Vertsplit zu verwenden, wenn alle Aufteilungsausdrücke benötigt werden.

1.6.6 Inneres Produkt

  内积,定义为< A , B > : = tr ( AB ) = ∑ i , j A i , j B i , j <A,B>:=tr(AB)=∑_{i,j}A_{ i,j}B_{i,j}<EIN ,B>:=t r ( A B )=ich , jAich , jBich , j, wie folgt erstellt:

x = SX.sym('x',2,2)
print(dot(x,x))

Die Ausgabe nach dem Ausführen ist:

(((sq(x_0)+sq(x_1))+sq(x_2))+sq(x_3))

  Viele der oben genannten Operationen sind auch für dünn besetzte Klassen definiert, und die Matrizen, die nach Operationen wie vertcat, horzsplit, transpose, Addition (gibt die Vereinigung zweier dünn besetzter Muster zurück) und Multiplikation (gibt den Schnittpunkt zweier dünn besetzter Muster zurück) zurückgegeben werden, sind ebenfalls definiert spärlich.

1.7 Abfrageattribute

  Sie können überprüfen, ob eine Matrix oder ein Sparse-Muster eine bestimmte Eigenschaft hat, indem Sie die entsprechende Memberfunktion aufrufen. Fragen Sie beispielsweise die Matrixgröße ab:

y = SX.sym('y',10,1)
print(y.shape)

Die Ausgabe nach dem Ausführen ist:

(10, 1)

  Zu den häufig verwendeten Operationen zum Abfragen der Attribute einer Matrix A gehören die folgenden:

Funktionsname Funktion
A.size1() Anzahl der Zeilen
A.size2() Anzahl der Spalten
Eine Form („Größe“ in MATLAB) Form, also das Paar (nrow, ncol )
Ein Name() Die Anzahl der Elemente, d. h. nrow*ncol
A.nnz() Die Anzahl der Nicht-Null-Elemente in der Struktur, wenn dicht, gleich A.numel().
A.sparsity() Rufen Sie einen Verweis auf den Sparse-Modus ab
A.is_dense() ist eine dichte Matrix, hat also keine strukturellen Nullstellen
A.is_scalar() Ist die Matrix ein Skalar, hat also die Dimensionen 1×1?
A.is_column() Eine Matrix ist ein Vektor, d.h. die Dimensionen sind n zu 1?
A.is_square() Ist die Matrix eine quadratische Matrix?
A.is_triu() Handelt es sich um eine obere Dreiecksmatrix?
A.is_constant() Sind alle Matrixeinträge konstant?
A.is_integer() 矩阵项都是整数值吗?

1.8 线性代数

  CasADi 支持有限数量的线性代数运算,例如 对于线性方程组的解:

A = MX.sym('A',3,3)
b = MX.sym('b',3)
print(solve(A,b))

运行后输出结果为:

(A\b)

1.9 微积分 - 算法微分

  CasADi 最核心的功能是algorithmic(or automatic)微分 (AD)。 对于函数 f : R N → R M f:\mathbb{R}^N→\mathbb{R}^M f:RNRM:
y = f ( x ) , y=f(x), y=f(x),
前向模式方向导数(forward mode directional derivatives)可用于计算 Jacobian-times-vector 乘积:

y ^ = ∂ f ∂ x x ^ \hat{y} = \frac{\partial f}{\partial x} \hat{x} y^=xfx^
类似地,反向模式方向导数(reverse mode directional derivatives)可用于计算雅可比转置时间向量乘积:
x ^ = ( ∂ f ∂ x ) T y ^ \hat{x} = (\frac{\partial f}{\partial x})^T \hat{y} x^=(xf)Ty^

  正向和反向模式方向导数的计算成本与评估 f(x) 成正比,而与 x 的维数无关。

  CasADi 还能够有效地生成完整的、稀疏的雅可比行列式。 其算法非常复杂,但基本上包括以下步骤:

  • 自动检测 Jacobian 的稀疏模式
  • 使用图着色技术找到构建完整雅可比行列式所需的一些前向和/或方向导数
  • 以数字或符号方式计算方向导数
  • 计算雅可比行列式

Hessian 的计算方法是首先计算梯度,然后执行与上述相同的步骤,以与上述相同的方式计算梯度的雅可比矩阵,同时利用对称性。

1.9.1 句法

  计算雅可比行列式的表达式:

A = SX.sym('A',3,2)
x = SX.sym('x',2)
print(jacobian(A@x,x))

运行后输出结果为:

[[A_0, A_3],
 [A_1, A_4],
 [A_2, A_5]]

  当微分表达式为标量时,还可以计算矩阵意义上的梯度:

print(gradient(dot(A,A),A))

运行后输出结果为:

[[(A_0+A_0), (A_3+A_3)],
 [(A_1+A_1), (A_4+A_4)],
 [(A_2+A_2), (A_5+A_5)]]

请注意,与 jacobian 不同,梯度始终返回一个密集向量。

Hessians 和作为副产品的梯度计算方法如下:

[H,g] = hessian(dot(x,x),x)
print('H:', H)

运行后输出结果为:

H: @1=2,
[[@1, 00],
 [00, @1]]

  对于计算雅可比乘法向量乘积,jtimes 函数——执行前向模式 AD——通常比创建完整雅可比矩阵和执行矩阵向量乘法更有效:

A = DM([[1,3],[4,7],[2,8]])
x = SX.sym('x',2)
v = SX.sym('v',2)
f = mtimes(A,x)
print(jtimes(f,x,v))

运行后输出结果为:

[(v_0+(3v_1)), ((4v_0)+(7v_1)), ((2v_0)+(8*v_1))]

jtimes 函数可选地计算转置雅可比次向量乘积,即反向模式 AD:

w = SX.sym('w',3)
f = mtimes(A,x)
print(jtimes(f,x,w,True))

运行后输出结果为:

[(((2w_2)+(4w_1))+w_0), (((8w_2)+(7w_1))+(3*w_0))]

Ich denke du magst

Origin blog.csdn.net/qq_16775293/article/details/117422579
Empfohlen
Rangfolge