2016-06-07 16 views
3

Ich benötige eine templated Sparse Matrix-Implementierung, aber nur um den Speicherbedarf zu reduzieren, nicht. Also habe ich versucht, Eigen zu verwenden, obwohl ich den Mathe-Teil nicht benötige. Warum ? Es lag zufällig auf meiner Maschine und ich hatte es schon ein wenig für andere Sachen benutzt. Aber ich bin sicherlich kein Eigenexperte!Kann ich für die allgemeinen Speicheranforderungen eigene Sparse-Matrizen verwenden?

Kontext: Ich habe eine Art T (sagen wir struct T{int a; float b; vector<int> c; }; und ich brauche große Matrizen diese speichern (zB mehr als 1000x1000) und die meisten Werte sind null/irrelevant

Da ich nicht tun. tun, um jede Mathe, ich obwohl es genug wäre, einen assignement Betreiber bietet Speicher-/Abrufoperationen, wie die folgenden Funktionen ausführen:

int main() 
{ 
    Eigen::SparseMatrix<MyClass> mat(1000,1000); // 1000000 elements 
    MyClass b{ 5, 1.2 }; 
    mat.insert(3, 4) = b; 
} 

So, hier ist ein Datentyp, mit dem, was ich dachte, war notwendig:

struct MyClass 
{ 
    int a; 
    float b; 
    std::vector<int> v_things; 

    MyClass(int aa, float bb) : a(aa), b(bb) {} 
    MyClass(const MyClass& other) // copy constructor 
    { 
     a = other.a; 
     b = other.b; 
     v_things = other.v_things; 
    } 
    MyClass& operator=(const MyClass& arg) 
    { 
     if(this != &arg) 
     { 
      MyClass tmp(arg); 
      std::swap(tmp, *this); 
     } 
     return *this; 
    } 
}; 

Aber dies nicht gelingt, zu kompilieren, weil es scheint, eine besondere Form des Zuweisungsoperators zu beantragen:

/usr/include/eigen3/Eigen/src/SparseCore/SparseMatrix.h:1146:27: error: no match for ‘operator=’ (operand types are ‘Eigen::internal::CompressedStorage<MyClass, int>::Scalar {aka MyClass}’ and ‘int’) 
    return (m_data.value(p) = 0);' 

(Compiler GCC 5.3 mit -std = C++ 11)

Fragen:

  • Ist es möglich, dies mit Eigen zu tun?
    • Wenn ja, was muss ich zum Datentyp hinzufügen? Ist das der beste Ansatz?
    • Wenn nein, hätten Sie Vorschläge zu einer anderen Bibliothek?

Relevante Eigen Handbuchseiten:

Antwort

4

der Tat, da sie ausgelegt ist numerische Werte zu speichern, wird Ihre Art soll konstruierbar sein/als aus dem wörtlichen 0 signierbar. Es benötigt wird, sicher, dass die Einlage (i, j) gibt eine Referenz auf einen Skalar auf 0

So können Sie durch Hinzufügen eines Dummy operator= Umgehung initialisiert zu machen:

MyClass& operator=(int x) { assert(x==0); /* ... */ return *this; } 

Edit:

Um setFromTriplets zu verwenden, müssen Sie auch operator+= angeben. Der Grund dafür ist, dass doppelte Einträge standardmäßig summiert werden. In Eigen 3.3 ist es sauberer, einen Funktor (z. B. ein Lambda) an setFromTriplets zu übergeben, der definiert, wie Duplikate zusammengeführt werden sollen.In Ihrem Fall könnte man einfach einen Funktor passiert eine Laufzeit Behauptung Auslösen, wenn sie aufgerufen wird:

mat.setFromTriplets(begin,end, [] (const MyClass& a,const MyClass &) { 
    assert(false && "found duplicates"); return a; }); 

In diesem Fall brauchen Sie nicht MyClass::operator+=

+0

Großer, @ggael, ich brauche auch eine leeren Standardkonstruktor hinzuzufügen und meinen ursprünglichen assignement Operator zu entfernen, sondern Werke gut jetzt. – kebs

+0

Update: alles in Ordnung, um einzelne Elemente zu schreiben/lesen, aber Batch-Einfügen ('setFromTriplets()') scheint auch einige '+ = 'Operator zu erfordern. Das ist seltsam für mich: Warum würde das Speichern von etwas im Speicher das erfordern? Und ich habe versucht, einen hinzuzufügen, aber gescheitert ... – kebs

+0

Fixed, werde ich eine andere Antwort mit Details posten. – kebs

0

zu definieren, die Antwort von @ggael gegeben Abwicklung und für diejenigen, die wollen würden, etwas ähnliches zu tun, hier ist eine komplette Probe, die kompiliert und ausgeführt:

#include <eigen3/Eigen/SparseCore> 
#include <vector> 
#include <iostream> 
struct MyClass 
{ 
    int a; 
    float b; 
    std::vector<int> v; 

    MyClass(){} 
    MyClass(int aa, float bb) : a(aa), b(bb) {} 
    MyClass(int aa): a(aa) {} 
    MyClass(const MyClass& other) // copy constructor 
    { 
     a = other.a; 
     b = other.b; 
     v = other.v; 
    } 
    MyClass& operator=(int x) 
    { 
     assert(x==0); 
     return *this; 
    } 

    MyClass& operator += (const MyClass& x) 
    { 
     return *this; 
    } 
}; 

void PrintMat(const Eigen::SparseMatrix<MyClass>& mat) 
{ 
    std::cout << "Matrix content:\n"; 
    for (int k=0; k<mat.outerSize(); ++k) 
     for(Eigen::SparseMatrix<MyClass>::InnerIterator it(mat,k); it; ++it) 
      std::cout << "row=" << it.row() << " col=" << it.col() 
       << ": a=" << it.value().a 
       << " b=" << it.value().b 
       << " vect size=" << it.value().v.size() << "\n"; 
} 

int main() 
{ 
    Eigen::SparseMatrix<MyClass> mat(1000,1000); // 1000000 positions 

    MyClass a{ 5, 1.2 }; 
    a.v.resize(5); 
    mat.insert(3, 4) = a; // insert single element 
    PrintMat(mat); 

    MyClass b{ 6, 2.3 }; 
    b.v.resize(9); 
    mat.coeffRef(3, 4) = b; // update single element 
    PrintMat(mat); 

    std::vector<Eigen::Triplet<MyClass>> tripletList; 
    for(int i=0; i<10; i++) 
    { 
     MyClass a{i*2,i*3.0f}; 
     tripletList.push_back(Eigen::Triplet<MyClass>(i,i*10,a)); 
    } 
    mat.setFromTriplets(tripletList.begin(), tripletList.end()); 
    PrintMat(mat); 
} 
Verwandte Themen