2016-06-07 3 views
3

Мне нужна схематичная разреженная матричная реализация, но только для уменьшения объема памяти, не делать какие-либо численные решения. Поэтому я попытался использовать Eigen, хотя мне не нужна математическая часть. Зачем ? Это просто лежало на моей машине, и я уже немного использовал его для других вещей. Но я, конечно, не эксперт Эйгена!Могу ли я использовать Eigen разреженные матрицы для общих требований к хранению

Контекст: У меня есть тип T (скажем struct T{int a; float b; vector<int> c; }; и мне нужно хранить большие матрицы этого (скажем, более чем 1000x1000) и большинство значений равны нулю/значения

Поскольку у меня нет. делать какие-либо математику, я, хотя это было бы достаточно, чтобы обеспечить оператору присваивания делать операции хранения/извлечения, как показано в следующем:

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

Так вот это тип данных, с тем, что я считал нужным:

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; 
    } 
}; 

Но это не удается скомпилировать, потому что кажется, просить какой-то особый вид оператора присваивания:

/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);' 

(составитель: GCC 5.3 с -std = C++ 11)

Вопросы:

  • Возможно ли это сделать с Eigen?
    • Если да, то что мне нужно добавить к типу данных? Это лучший подход?
    • Если нет, у вас есть предложение по другому либрите?

Соответствующие Собственные страницы руководства:

ответ

4

Действительно, так как он предназначен для хранения числовых значений, ваш тип должен быть конструктивным/как можно подписать из литерала 0. Это необходимо, чтобы убедиться, что вставка (I, J) возвращает ссылку на скаляр инициализируется 0.

Таким образом, вы можете обходной путь добавив фиктивный operator=:

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

Edit:

Чтобы использовать setFromTriplets, вам также необходимо указать operator+=. Причина в том, что по умолчанию дублированные записи суммируются. В Eigen 3.3 чище пропускать функтор (например, лямбда) до setFromTriplets, определяющий, как дубликаты должны сливаться.В вашем случае, вы могли бы просто передать функтор запускающего среды выполнения утверждение, если оно называется:

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

В этом случае вам не нужно определить MyClass::operator+=

+0

Отлично @ggael, я также нужно добавить пустой конструктор по умолчанию и удалить мой исходный оператор присваивания, но работает сейчас хорошо. – kebs

+0

Обновление: все нормально писать/читать отдельные элементы, но пакетная вставка ('setFromTriplets()'), по-видимому, требует также некоторого оператора '+ ='. Это странно для меня: зачем хранить что-то в памяти? И я попытался добавить один, но не удалось ... – kebs

+0

Исправлено, я отправлю еще один ответ с подробностями. – kebs

0

Чтобы завершить ответ дается @ggael и для тех, кто хотел бы сделать что-то подобное, вот полный пример, который компилируется и работает:

#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); 
}