Re: [eigen] On a flexible API for submatrices, slicing, indexing, masking, etc.

[ Thread Index | Date Index | More Archives ]

On Sat, Jan 7, 2017 at 4:05 PM, Gael Guennebaud <gael.guennebaud@xxxxxxxxx> wrote:

On Sat, Jan 7, 2017 at 4:35 PM, Yuanchen Zhu <yuanchen.zhu@xxxxxxxxx> wrote:

Actually using explicit bound functions has the benefit that you no longer need fixed<C>, i.e.:

aseq(a, 10, s) =  a + iota * s | _1 <= fixed<10> 
aseq(a, 10, s) =  a + iota * s | ubound<10>

This got me thing. Maybe, pipe '|' + ​sequence wide function is a better alternative.  I've edited the wiki to explain. See

I am quoting the wiki below:

Part of the reason that we are considering implementing bounds either using relationship operators or predicates is that we want to easily represent an seq(first, last, incr) sequence. However, at the end of the day, neither allows a completely generic seq to be written trivially, since the comparison _expression_ needs to take into account the sign of incr:

seq(a, b, d) = a <= a +iota* d <= b  if d > 0
seq(a, b, d) = a >= a +iota* d >= b  if d < 0

seq(a, b, d) = a + iota * d | ubound(b) if d > 0
seq(a, b, d) = a + iota * d | lbound(b) if d < 0

Another possible convention (e.g., range v3) is that S | F means invoking a sequence-wide function F on the entire sequence of S, relying on the unix pipe connotation. Adopting that convention, to apply a general predicate P, we write

a + iota * s | filter(P) // 

So it's not as simple as a + iota * s | P, But the benefit is that more general purpose sequence-wide function can be used, not just predicates. Moreover, the definition of previously named predicate like ubound and lbound can be changed to work on the whole sequence, so in practice one can still write

a + iota * s | ubound(b)

Now note that the _expression_ first + iota * incr produces an (infinite) arithmetic progression. We can define a sequence wide function until(bound) that only makes sense for infinite arithmetic progressions, i.e.

a + iota * s | until(b) = seq(a, b, s)

So until(bound) truncate an infinite arithmetic progression to stop at bound. It automatically takes into consideration the direction of the progression (increasing, or decreasing), so no special handling based on the sign of incr is needed, in contrast to the case of relationship operator and predicate based notations.

Finally this use of the pipe operator is completely in line with range v3, which might one day becomes STL2.

Then just use range-v3, it's readily compatible with the current implementation of Indexed-View in my Eigen's fork ( For instance, the following does work:

using namespace ranges::view;
A(ints(1) | take(5), iota(1,10) | stride(2)) ==  A(seq(1,5),seq(1,9,2));
Of course, it currently does not work for ranges that does not support random-access.

Just plugging  range-v3 has a few downsides:

- There is no notion of arithmetic progression and what operations preserve its property. Indexing using AP is going to be faster than an indexed-view.

- It does not allow compile time constant parameters of the form iota<n>.

- Since it works with sequences of anything, it doesn't support arithmetic overloads like + and *. Writing "a + iota * s" is still superior to something like "iota | stride(s) | offset(a)"

Mail converted by MHonArc 2.6.19+