2017-06-05 1 views
1

Ich kämpfe mit der Tatsache, dass Elemente von sympy.MatrixSymbol scheinen nicht gut mit Sympy Differenzierung Routinen zu interagieren.sympy.MatrixSymbol: Probleme mit der Differenzierung

Die Tatsache, dass ich versuche, mit Elementen von sympy.MatrixSymbol statt "normalen" sympy Symbole zu arbeiten, ist, weil ich eine große Funktion autowrap, und dies scheint, dass dies der einzige Weg ist, Argument Einschränkungen zu überwinden und Aktivieren Sie die Eingabe eines einzelnen Arrays.

Um dem Leser ein Bild von den Einschränkungen möglicher Lösungen zu geben, werde ich mit einem Überblick über meine Absichten beginnen; Der hastige Leser könnte aber auch zu den Codeblöcken springen, die mein Problem illustrieren.

  1. Deklarieren Sie einen Vektor oder ein Array von Variablen in irgendeiner Form.

  2. Erstellen Sie einige Ausdrücke aus den Elementen des ersteren; Diese Ausdrücke sollen die Komponenten einer Vektorwertfunktion des Vektors bilden. Zusätzlich zu dieser Funktion möchte ich die Jacobi w.r.t erhalten. der Vektor.

  3. Verwenden Sie Autowrap (mit dem Cython-Backend), um numerische Implementierungen der Vektorfunktion und ihrer Jacobi zu erhalten. Dies stellt einige Einschränkungen für die früheren Schritte dar: (a) Es ist erwünscht, dass die Eingabe der Funktion als ein Vektor anstatt einer Liste von Symbolen gegeben ist. (Beide, weil es anscheinend eine Grenze für die Anzahl von Eingaben für eine automatisch umschlossene Funktion gibt, und um die Interaktion mit scipy später zu erleichtern, d. H. Es wird vermieden, häufig numpige Vektoren in Listen zu entpacken).

Auf meiner Reise traf ich zwei Fragen:

  • Cython scheint nicht etwas sympy Funktion zu mögen, darunter sympy.Max, auf die ich stark angewiesen. Der "Helfer" -Kwarg des Autowrap scheint nicht in der Lage zu sein, mehrere Helfer gleichzeitig zu behandeln.
  • Dies ist an sich keine große Sache, wie ich gelernt habe, um es zu umgehen mit abs() oder sign(), die Cython leicht versteht.

(siehe auch this question auf der oben)

  • Wie bereits erwähnt, autowrap/cython nicht mehr als 509 Argumente in Form von Symbolen akzeptieren, zumindest nicht in meinem Compiler-Setup. (Siehe auch here)
  • Da ich lieber einen Vektor als eine Liste als Eingabe für die Funktion geben würde, suchte ich nach einer Möglichkeit, um die Wrapped-Funktion ein numpiges Array als Eingabe zu erhalten (vergleichbar mit DeferredVector +) Lambdify). Es scheint der natürliche Weg dies zu tun ist sympy.MatrixSymbol. (Siehe Thread oben verlinkt. Ich bin nicht sicher, dass es eine Alternative geben würde, wenn ja, Vorschläge sind willkommen.)

  • Mein neuestes Problem beginnt dann hier: Ich erkannte, dass die Elemente von sympy.MatrixSymbol in vielerlei Hinsicht Benimm dich nicht wie "andere" sympy Symbole. Man muss die Eigenschaften real und kommutativ einzeln zuweisen, was dann aber gut zu funktionieren scheint.Mein richtiges Problem beginnt jedoch, wenn ich versuche, die Jacobi zu bekommen; sympy scheint keine Derivate der Elemente direkt aus der Box zu bekommen:

import sympy 

X= sympy.MatrixSymbol("X",10,1) 

for element in X: 
    element._assumptions.update({"real":True, "commutative":True}) 

X[0].diff(X[0]) 
Out[2]: Derivative(X[0, 0], X[0, 0]) 


X[1].diff(X[0]) 
Out[15]: Derivative(X[1, 0], X[0, 0]) 

Der folgende Block ist ein minimales Beispiel dafür, was Ich mag würde zu tun, aber hier normale Symbole verwendet: (ich glaube, es fängt ich brauche, wenn ich etwas vergessen haben, ich später hinzufügen werden.)

import sympy 
from sympy.utilities.autowrap import autowrap 

X = sympy.symbols("X:2", real = True) 
expr0 = X[1]*((X[0] - abs(X[0])) /2)**2 
expr1 = X[0]*((X[1] - abs(X[1])) /2)**2 
F = sympy.Matrix([expr0, expr1]) 
J = F.jacobian([X[0],X[1]]) 
J_num = autowrap(J, args = [X[0],X[1]], backend="cython") 

Und hier ist meine (derzeit) best guess sympy.MatrixSymbol verwenden, die dann natürlich, weil die Derivative versagt -expressi ons in J:

X= sympy.MatrixSymbol("X",2,1) 
for element in X: 
    element._assumptions.update({"real":True, "commutative":True, "complex":False}) 
expr0 = X[1]*((X[0] - abs(X[0])) /2)**2 
expr1 = X[0]*((X[1] - abs(X[1])) /2)**2 
F = sympy.Matrix([expr0, expr1]) 
J = F.jacobian([X[0],X[1]]) 
J_num = autowrap(J, args = [X], backend="cython") 

Hier ist, was J wie sieht die oben nach dem Laufen:

J 
Out[50]: 
Matrix([ 
[(1 - Derivative(X[0, 0], X[0, 0])*X[0, 0]/Abs(X[0, 0]))*(-Abs(X[0, 0])/2 + X[0, 0]/2)*X[1, 0], (-Abs(X[0, 0])/2 + X[0, 0]/2)**2], 
[(-Abs(X[1, 0])/2 + X[1, 0]/2)**2, (1 - Derivative(X[1, 0], X[1, 0])*X[1, 0]/Abs(X[1, 0]))*(-Abs(X[1, 0])/2 + X[1, 0]/2)*X[0, 0]]]) 

Welche, wenig überraschend, hat autowrap nicht mag:

[...] 
wrapped_code_2.c(4): warning C4013: 'Derivative' undefined; assuming extern returning int 
[...] 
wrapped_code_2.obj : error LNK2001: unresolved external symbol Derivative 

Wie kann ich sympy sagen dass X[0].diff(X[0])=1 und X[0].diff(X[1])=0? Und vielleicht sogar das abs(X[0]).diff(X[0]) = sign(X[0]).

Oder gibt es einen Weg um mit sympy.MatrixSymbol und still get a cythonized function, wo die Eingabe ist ein einzelner Vektor und nicht eine Liste von Symbolen?

Wäre für jede Eingabe gut, möglicherweise eine Problemumgehung bei jedem Schritt des oben beschriebenen Prozesses. Danke fürs Lesen!


Edit:
Eine kurze Bemerkung: Eine Lösung, die ich mit mir selbst kommen konnte, ist dies: Construct F und J normale Symbole; Ersetzen Sie dann die Symbole in beiden Ausdrücken durch die Elemente eines sympy.MatrixSymbols. Dies scheint den Job zu erledigen, aber der Austausch dauert sehr lange, da J Dimensionen von ~ 1000x1000 und darüber erreichen kann. Ich würde es daher vorziehen, einen solchen Ansatz zu vermeiden.

Antwort

1

Nach eingehenderer Forschung scheint das oben beschriebene Problem bereits in der Entwicklung/github Version behoben zu sein. Nach einer entsprechenden Aktualisierung werden alle Derivative Bedingungen mit MatrixElement korrekt aufgelöst!

Siehe here als Referenz.