2015-03-10 15 views
5

Wir versuchen, einen neuen C++ Code in meiner Forschungsgruppe zu implementieren, um große numerische Simulationen (Finite Elemente, Finite-Differenzen-Methoden, Topologieoptimierung, etc.) durchzuführen wird von Menschen aus Wissenschaft und Industrie gleichermaßen genutzt werden.Wie schreibe ich eine Wrapper-Klasse von Drittanbietern um Expressionsvorlagen

Für die dichte lineare Algebra Stück der Software wollen wir entweder Eigen oder Armadillo verwenden. Wir möchten aus zwei Gründen einen Wrapper um diese Pakete erstellen: 1. um unsere eigene API den Benutzern und nicht der API des Drittanbieters zugänglich zu machen; und 2. falls wir Bibliotheken in der Zukunft wechseln müssen. Ich verstehe Grund 2 ist eine sehr teure Form der Versicherung, aber wir haben diese Situation mit unserer vorherigen Simulationssoftware begegnet.

Die Informationen, die ich erlebt habe in Bezug auf Bibliotheken von Drittanbietern Verpackung kommt aus diesen Quellen:

Meine Frage bezieht sich in Bezug auf die beste Art und Weise zu Erstellen Sie diese Wrapperklasse. Idealerweise wäre eine Dünnschichtumhüllung die beste, wie zum Beispiel:

oder deren Äquivalent mit einem Eigenvektor.

Dann nennen würde meine Klasse, die von Drittanbietern Bibliothek Klasse:

my_vec::foo() { return _arma_vec.foo(); } 

Ich denke (und ich würde Bestätigung auf dieser mag), dass das Problem mit dieser dünnen Schicht ist, dass ich die Geschwindigkeit gewonnen verlieren Aus den Expression Templates haben diese Bibliotheken unter der Haube implementiert. Zum Beispiel in Armadillo, die folgende Operation:

// Assuming these vectors were already populated. 
a = b + c + d; 

wird so etwas wie dieses:

for (std::size_t i = 0; i < a.size(); ++i) { 
    a[i] = b[i] + c[i] + d[i]; 
} 

ohne Provisorien aufgrund ihrer Umsetzung expression templates zu schaffen. Die gleiche Situation gilt für Eigen.

Soweit ich das verstehe, der Grund, warum ich die Macht der Ausdruck Vorlagen verliere, ist, dass während Armadillo oder Eigen nicht provisorische eigene erstellen, meine Klasse my_vec tut. Die einzige Möglichkeit, dies zu umgehen, wäre, einen Thin-Layer-Wrapper um ihre Expression-Templates zu erstellen. An dieser Stelle scheint dies jedoch eine Verletzung des YAGNI-Prinzips zu sein.

Diese damit verbundene Frage hier:

schlägt vor, wie etwas mit:

my_vec a, b, c; 
// ... populate vectors 
a._arma_vec = b._arma_vec + c._arma_vec; 

Ist es möglich, so etwas wie dieses, anstatt zu benutzen?

template< typename T > 
arma::Col<T> & 
my_vec<T>::data() { return _arma_vec; } 

a.data() = b.data() + c.data(); 

Oder verwenden Sie einen Operatorüberladung, um data() vor dem Benutzer zu verstecken? Welche anderen Alternativen gibt es, wenn wir die Bibliotheken nicht direkt verwenden möchten? Makros verwenden? Verwenden von Aliasen, wenn wir uns für C++ 11 entscheiden?

Oder was wäre der bequemste Weg, um diese Wrapper-Klasse zu erstellen?

Antwort

1

nur für die Zukunft, das ist, wie ich meine Lösung zu implementieren entschieden: Ich habe den Betreiber überlastete + auf folgende Weise:

template< typename T1, typename T2 > 
auto 
operator+(
     const my_vec<T1> & X, 
     const my_vec<T2> & Y) ->decltype(X.data() + Y.data()) 
{ 
    return X.data() + Y.data(); 
} 

template< typename T1, typename T2 > 
auto 
operator+(
     const my_vec<T1> & X, 
     const T2 &   Y) ->decltype(X.data() + Y) 
{ 
    return X.data() + Y; 
} 

template< typename T1, typename T2 > 
auto 
operator+(
     const T1 &   X, 
     const my_vec<T2> & Y) ->decltype(X + Y.data()) 
{ 
    return X + Y.data(); 
} 

Dann habe ich überlastete meinen Operator = in my_vec Klasse mit dem folgenden:

template< typename T > 
template< typename A > 
const my_vec<T> & 
my_vec<T>::operator=(
     const A & X) 
{ 
    _arma_vec = X; 

    return *this; 
} 
+0

Ich bin gerade auf diese Frage gestoßen - und ich versuche auch, ein ähnliches Ziel zu erreichen. Ein paar Fragen kamen in den Sinn, wenn Sie Ihren Code betrachteten: 1. Hat Ihre Wrapper-Klasse nur ein privates Vektorelement? Haben Sie für ein Matrixelement eine andere Wrapperklasse geschrieben? 2. Wie haben Sie die Matrixvektormultiplikation durchgeführt? 3. Erhält Ihre Implementierung die Effizienz von Ausdrucksvorlagen? – endbegin

+0

1. Ja. Oder eine Zeile oder ein privates Matrix-Mitglied. Sie können entweder einen Wrapper für jede Klasse (Col, Row, Mat) schreiben oder einfach eine Matrix für alles verwenden und einen einzelnen Wrapper schreiben. 2. Sie können mehrere Wrapper oder einen einzelnen Wrapper schreiben, wie ich in 1. gesagt habe. Dann müssten Sie Operatoren überladen. 3. Es ist effizient, aber nie so effizient wie die rohe Implementierung. Ich würde sagen, wir verlieren irgendwo zwischen 1 und 10% Effizienz in der Rechenzeit. Was wir gewinnen, ist die Fähigkeit, zwischen Bibliotheken zu wechseln. Im Moment können wir einfach zwischen Eigen und Armadillo wechseln, ohne die öffentliche API zu ändern. –

+0

Ich habe versucht, eine einzige Matrix-Wrapper-Klasse für Matrizen und Vektoren zu schreiben, nur damit ich die überladenen Operatoren in eine Wrapper-Datei schreiben kann. Eigen macht es jedoch nicht einfach. Ich hätte gerne nur ein privates Mitglied - eine nicht initialisierte Matrix - die so skaliert werden kann, dass sie sowohl eine MxN-Matrix als auch ein Mx1-Vektor ist, aber Eigenvektoroperationen (wie Dotprod) funktionieren nicht Ein Vektor muss als Matrix initialisiert werden. – endbegin