Re: [eigen] Sparse usage feedback

[ Thread Index | Date Index | More lists.tuxfamily.org/eigen Archives ]


Hi Geal,



Thanks for your answers. I reply "inline".



> 

> I could consider to give it a try if and only if the begin()/end()

> paradigm would bring any additional benefits than just being closer to

> the STL. The current approach has the advantage to be simpler to use

> (e.g., no need to declare an end iterator). Well, actually I'm

> thinking that having an access to the end() might be useful but I'm

> still a bit worried about the performance and the API verbosity.

> 



In fact, my wish for more idiomatic iterators doe not stems from the

abstract love of iterator pairs, but from the practical desire to reuse

idiomatic code (such as the STL itself) on sparse matrix data ! :)

[more below ]



> Here is an example of what could be the API:

> 

> SparseMatrix m;

> 

> for(int j=0;j<m.outerSize();++j)

> {

>   SparseMatrixType::InnerIterator end(m.innerVector(j).end());

>   for(SparseMatrixType::InnerIterator it(m.innerVector(j).begin());

> it!=end; ++it)

>     ...;

> }



That would be good. I also pondered about an API inspired from

tr1::unordered_map :

http://publib.boulder.ibm.com/infocenter/comphelp/v9v111/index.jsp?topic=/com.ibm.xlcpp9.aix.doc/standlib/stl_unordered_map.htm



with .begin(IndexType) & .end(IndexType).



[more below]

> 

>> 2°) The iterator do not expose row() and col() through an iterator

>>

>> interface

>>

>> (i.e. with operator*()) which make it impossible to manipulate

sequences

>>

>> of

>>

>> coords with the standard algorithms operating on iterator sequences.

> 

> Sorry, but I don't really understand what you are looking for here,

> can you be more specific please?



I meant that you can have access to all the relevent info with your

current API,

but not through an "itarator API" because you get them by calling member

functions 

it.value();

it.row();   // row index

it.col();   // col index (here it is equal to k)

it.index(); // inner index, here it is equal to it.row()



which means that you cannot replace your loops with calls to std

algorithms.

I.e, I'd like to rewrite your previous example as :

SparseMatrix m;

 

for(int j=0;j<m.outerSize();++j)

  std::for_each(m.innerVector(j).begin(), m.innerVector(j).end(), …);



But it means that the iterators must return the relevent info through the 

idiomatic operator*() instead of custom member functions (.value(),…).



I wrote iteratorS because as you only have one operator*(), you'd have to

give more than one iterator, or you'd make your user pay for unused data.

(i.e you could give rowsCols(j).begin()/.end() with operator*() returning

and std::pair<IndexType, IndexType>

and values(j).begin()/.end() returning a Scalar.



Failing to do that means giving up on the std algorithms (or having to

rewrite them

as does GIL : 

http://stlab.adobe.com/gil/html/giltutorial.html#STLEquivalentsSec



Btw, I'll also investigate whether it would be prohibitively expensive to

allow

 std::for_each(m.begin(), m.end(), …);

to walk the whole matrix.(IMVHO, for sparse matrices, you don't usually

fit many 

matrices in L1 cache so the extract checks will be lost in the data fecth

latency).





> 

>> 3°) This is not possible to construct a Sparse from a Dense

>>

> 

> This is already possible:

> 

> sparse = dense.sparseView();

> sparse = dense.sparseView(ref,epsilon); // skip coefficients smaller

> than ref*epsilon



Thanks. I missed (and I think it should deserve some ref in 

http://eigen.tuxfamily.org/dox-devel/TutorialSparse.html



However, I think that Sparse classes should have constructors taking dense

matrices

calling sparseview() because if you can construct an object of class A

from 

an object of classe B, the idiomatic way to do it in C++ is to have a A(B

const&)

constructor.





> 

> 

>> 4°) I think some scalar operation traits are missing

>>

>> (i.e. trying to multiply an int matrix with a double fails to find

>>

>> ‘struct Eigen::ei_scalar_product_traits<double, int>’ )

> 

> This is because this is explicitly not allowed. You have to explicitly

> cast the int matrix to double. Our opinion is that such an automagic

> cast would be dangerous.



When sizeof(int)*8 <= std::numeric_limits<double>::digits I believe that

such

a cast is not dangerous (and I have 32 bits for ints and 53 bits for

double).



However, I think maybe a catch all template could be used to give an hint

to the

problem with an helpful message in the source code of this template

(designed to trigger an error)

such as /* no implicit cast provided, use the .cast<> template member

function 

to mix those types*/).



> 

>> 5°) I think that the typedefs in i.e.  SparseLU<> should be public

>>

>> I may need to know the LMatrixType & cie to make some metaprogramming

of

>>

>> my own

>>

>> (or did I missed some traits struct ?)

> 

> Yes you are right. All these decompositions/solvers require a lot of

> polishing, and actually I've already started a rewrite of them with a

> slightly simpler/safer API. The main change is that I'm removing these

> Backend template parameters.



I am very interested in this !

Where is it availbale ?



Currently, I'm giving the backend choice at runtime and deriving

the implementations with dynamic dispatching.

    template<typename Backend> struct LUFact : LUFactBase



and I convert the returned matrices types to a Backend-independant

sparse type.



As I wrote above, I think that sparses matrices (contrary to dense

matrices)

are never small enough to mandate the all same optimizations as dense

matrices.

For instance, I can't think of a relevent use case forbidding dynamic

dispatching

(maybe using covariant return type if various backend return different

concrete

implementations for the result matrices of the LU decompositions).



Best regards,



Bernard





Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/