2017-07-03 10 views
0

Ich verwende Eigen für eine große, spärliche Matrix von (in diesem Beispiel) Dimensionen 2e8 x 1e6, die höchstens 128 Elemente in jeder Zeile hat. Gemäß dem docs rufe ich reserve auf, um Speicher zuzuordnen, bevor die Nicht-Null-Elemente eingefügt werden. Bei großen Matrizen löst reserve eine std::bad_alloc Ausnahme aus.Zuordnung Ausnahme in Eigen :: SparseMatrix :: Reserve

#include <iostream> 
#include <Eigen/Core> 
#include <Eigen/Sparse> 

int main() 
{ 
    typedef Eigen::SparseMatrix<float, Eigen::RowMajor, long long int> SparseMat; 

    size_t n = 1000000, r = 200; 
    SparseMat T (r*n, n); 

    std::cerr << "Reserving memory" << std::endl; 

    size_t q = 128; 
    T.reserve(Eigen::VectorXi::Constant(r*n, q)); 

    std::cerr << "Ready to start inserting elements..." << std::endl; 
} 

Kompilieren mit clang++ oder g++ auf Ubuntu 16.04 führt den std::bad_alloc Ausnahme während der Laufzeit:

$ clang++ -march=native -O3 -isystem eigen-3.3.3 test_sparse.cpp -o test_sparse && ./test_sparse 
Reserving memory 
terminate called after throwing an instance of 'std::bad_alloc' 
    what(): std::bad_alloc 
[1] 26431 abort  ./test_sparse 

Verringerung der Anzahl der Nicht-Null-Elementen pro Zeile q = 49 oder darunter läuft gut. Einstellung q = 50 oder höher erzeugt den Fehler. Ähnliche Tests gelten für die Matrixgröße.

Beachten Sie auch, dass ich explizit den 64-Bit-Integer-Typ für die StorageIndex verwenden. Es ist mein Verständnis, dass 64-Bit ausreichend sein sollte, um die 1.28e8 Nicht-Null-Elemente in dieser Matrix zu indizieren, weil sie kleiner als 2^63-1 = 9.2e18 ist. Im Limit sollte es sogar ausreichen, eine dichte Matrix dieser Größe zu indizieren (2e8 x 1e6 = 2e14 < 9.2e18).

Daher meine Fragen sind:

  1. Am ich richtig anzunehmen, dass die 64-Bit-StorageIndex für diese Matrix Dimensionen ausreichend ist?

  2. Wenn ja, ist das ein Fehler oder ist in meinem Beispiel etwas falsch?

  3. Wenn nicht, ich habe auch versucht, __int128_t, aber das erzeugt den folgenden Compiler-Fehler: EIGEN_STATIC_ASSERT(NumTraits<StorageIndex>::IsSigned,THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE); Wie kann ich die relevanten Merkmale hinzufügen?

  4. Kann dieses Problem schließlich umgangen werden, indem zum Beispiel die Initialisierung von Triplets verwendet wird?

+0

Ich bin nicht mit Eigen vertraut, aber wie viele Bytes von Daten versuchen Sie zu reservieren und haben Sie genug Speicher haben? –

+0

Guter Punkt, meine 64 GB sind nicht ausreichend für 128 Elemente pro Zeile. – ChD

Antwort

0

std::bad_alloc normalerweise bedeutet, dass Sie nicht genügend Arbeitsspeicher lief und da Sie ~ 100 GB zuweisen versuchen, das überrascht mich nicht

T.reserve(Eigen::VectorXi::Constant(r*n, q)); ordnet q n * r * = 1000000 * 200 * 128 Schwimmer im Speicher .

Nicht sehr viele Maschinen auf dem aktuellen Stand der Technik kann so viel Speicher bieten

+0

Sie machen einen ausgezeichneten Punkt, 128 Floats pro Zeile passen zwar nicht in den 64GB RAM, den ich zur Verfügung habe, obwohl das Beispiel für 'q = 50' sollte (~ 37GB). Irgendwelche Vorschläge, wie man das umgehen kann (außer mehr Speicher zu bekommen)? – ChD

+0

@ChD Ist das ein zusammenhängendes Stück Speicher? In diesem Fall ist möglicherweise aufgrund von Fragmentierung nicht genügend Arbeitsspeicher verfügbar. –

+0

Ja, ich denke es ist. Auch die 37GB für q = 50 wären nur für die Werte (Matrixkoeffizienten), während ihre Indizes gleich viel Platz einnehmen würden. Ich habe q = 8 für einige Zeit verwendet, sogar auf 8GB-Systemen, und Speicher war nie der Flaschenhals. Aber für die erweiterte Matrix ist es eindeutig. Danke, dass du mich darauf hingewiesen hast.Ich werde die Problemformulierung überdenken müssen :-) – ChD

Verwandte Themen