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 2:51 AM, Gael Guennebaud <gael.guennebaud@xxxxxxxxx> wrote:On Thu, Jan 5, 2017 at 9:10 PM, Yuanchen Zhu <yuanchen.zhu@xxxxxxxxx> wrote:On Thu, Jan 5, 2017 at 11:07 AM, Gael Guennebaud <gael.guennebaud@xxxxxxxxx> wrote:Is this iota comparison syntax standard in APL or elsewhere?I don't know much about APL, I've been inspired by this post:for the size-based version first+iota(size)*step, and then came up with the use of comparison operators to cover the aseq(first,last) version. Last Massimilliano's post seems to imply that APL also uses this strategy to define bounds...Just from googling around, I couldn't confirm APL allows this.We already established that iota is basically aseqn. I think the notational advantage is that you can omit the "first", "incr" parameter when they're not needed. Also you have a natural notation for the common case where incr is fixed<-1>, just put "-" in front of iota.aseqn(0, n) = iota(n)aseqn(0, n, fix<-1>) = -iota(n)aseqn(0, n, s) = iota(n) * saseqn(a, ...) = a + ...We now just need a syntax to cover aseq. But I really don't think "<" is a good choice.If we view the result of iota and iota(n) as a pseudo vector, then the meaning of iota < C should not be different from v < C where v is a regular vector. Assume we still want to allow boolean mask indexing of the form v[v >= 3 && v < 5] to work, then v < C is a boolean vector.so far I tried to unify the two uses of this _expression_-based syntax but since I cannot see real examples that would mix the size-based iota(n) with "<" bounds, we could rephrase the two use cases more distinctly:1 - b+s*iota(n)2 - Let "any_nat" be a placeholder for any natural number (on a paper you would write forall i in N),then we define "lower <= any_nat*s+b <= upper" as shortcut for the set { x=i*s+b s.t., i in N and lower<= x <= upper }This got me thinking. How about the following:A predicate P is a boolean _expression_ that can be evaluated on a number.An ordered sequence S can be filtered by a predicate P, written as S | P = ( s | s in S and P(s) ). I used "()" here to denote ordered sequence. I chose "|" since it is used in set notation { x | predicate on x }. I call it the "such that" operator.To form simple predicate, one can use a placeholder like _1 (alias from std::placeholder, or introduce a new one), e.g, the _expression_ _1 < 10 returns a predicate that returns true for anything number less than 10.Then we simply have:aseq(a, b, s) = a + iota * s | _1 <= b (for s > 0)
This is not much more complex than a + any_nat * s <= b that you proposed, but is conceptually clean, and a lot more extensible: The such-that operator | (Vector v, Predicate p) is properly defined for any vector and predicate. In the most general case, p is an actual functor, so v | p needs to evaluate p on every element of v to create the new sequence. However, with proper overloads, we can recognize expressions such as "10 <= _1 < n" as bounding predicate. Any arithmetic progression filtered by a bounding predicate will simply return another arithmetic progression.Another possible convention (e.g., range v3) is that S | F means invoking a function F on the entire sequence of S, relying on the unix pipe connotation, in which case we need to writeaseq(a, b, s) = a + iota * s | filter(_1 <= b)So that's pretty close to what you would write on a paper, and this cannot be confused with boolean masking anymore. Then, thanks to implicit bounds we have:A(any_mat) <--> A(all)and thus we could (perhaps) just use "all" as a shortcut for "all natural numbers", leading to:"lower <= all*s+b <= upper"??On true drawback is that when you combined it with fix<X>, it gets a bit messy with all these "<",">":A(3<=(fix<2>*all)<10) // [3,5,7,9] <--> A(aseq(3,9,fix<2>))but with extra parenthesis it's not that bad.gael
Mail converted by MHonArc 2.6.19+ | http://listengine.tuxfamily.org/ |