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

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




On Fri, Jan 6, 2017 at 10:35 PM, Yuanchen Zhu <yuanchen.zhu@xxxxxxxxxx> wrote:


On Fri, Jan 6, 2017 at 3:50 AM, Massimiliano Janes <max.jns@xxxxxxxxx> wrote:

[…]. Last Massimilliano's post seems to imply that APL also uses this strategy to define bounds...

gael

I didn’t mean that sorry, I was just referring to the general idea behind APL's iota function, eg. transform
an integer N into the sequence [1,…,N], then *lazily* apply operations like arithmetics, transpositions
,etc… to create/manipulate vectors.

the API you’re proposing clearly differs in that N is given by the 'source’ vector, and the resulting index set
is clamped to fit in, but the idea ( and its benefits ) seems the same conceptually …

as an alternative to gael’s iota < bounds, one could follow more closely APL by introducing an _expression_
representing the number of source elements:

A(iota(all)) // as A(all)
A(iota(5)) // first five elements
A(2+iota(5)) // from index 2 to 6 
A(2*iota(all) ) // even numbers

​In general, I think the behavior of how Iota or Iota(all) is auto-bounded needs further discussion.

Are out of bounds indices automatically pruned for expr involving Iota? Does A(-3 + Iota) generate an error upon indexing? What about A(-3 + iota(3))?

ok, I think I made big mistake in naming Iota as iota(n), it clearly confuses you. Let's rename it "any_nat" for now and interpret it as a placeholder. This is really what I had in mind first, but I somehow thought it would be nice to merge the initial iota(n) API with this "any_nat+optional bounds" one. So once you completely separate them and think in terms of a any-natural-number placeholder, everything should become clear:

- The initial, APL-like iota(n) function defines a sequence with precise bounds that you can then manipulate. No implicit bounds here. So if size(A)==n, then:

A(2*iota(n) )

will raise an out-of-bound assertion. Writing A( 2*iota(n) <= last ) would not be allowed, as you noticed, this would be too confusing. Basically, we could also apply the same principle to seq, seqN. iota(n) would then simply be a shortcut for seqN(0,n)==seq(0,n+1).


- Then, for the "any_nat" approach, the general syntax would be:

a <= (an _expression_ using any_nat) <= b

Of course, you can use <= or <. Then, as in python, it is convenient to define default values for the bounds: a=0, and b=last. That's all.

So for instance, A(a<(-3+any_nat)<b) == A(a<any_nat<b). Adding an offset to any_nat makes sense only if you change the increment as in the "all odd numbers in [a,b]" example:

A(a<=(2*any_nat+1)<=b)

This one is a pain to express with all other API if you cannot guarantee that 'a' is odd itself. Want to reverse the order? just use -any_nat. Nothing else to worry about.

And yes, a<=any_nat does not return a boolean or a vector of booleans, but once put using this new wording, how could it be?


gael

 
A(2*iota(5) ) // even numbers up to 8
A(3+2*iota(all-2) ) // 3,5,7,… up to N-2
A(all - iota(5) ) // N-1,N-2,..,N-5
...

where bound checking is meant to follow Eigen habits ( eg. hard error if compile time, assert on runtime )




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