jsoftware / jsource

J engine source mirror
Other
645 stars 91 forks source link

Negative shape #137

Open rdm opened 2 years ago

rdm commented 2 years ago

J's $ verb should accept negative left arguments, similar to how i. and {. (and friends) accept negative arguments.

_3 $ 'abcdefg' should return 'efg' and _3 $'ab' should return 'bab'

moon-chilled commented 2 years ago

what is _4 _4$'abc'?

rdm commented 2 years ago

That's a good question.

I expect that it should correspond as much as possible with the behavior of {.

So, here are some examples (I'm skirting a length error here, but I think I'm being consistent with row-major order):

   _4 _4 {.!.'.' 'a'
....
....
....
...a
   _4 _4 {.!.'.' ,:'abc'
....
....
....
.abc

In other words, I am expecting _4 _4$'abc' to be the same as 4 4$(*/4 4)$&.|.'abc'

   4 4$(*/4 4)$&.|.'abc'
cabc
abca
bcab
cabc

Thinking about this a little further, I expect that the index order of i._4 _4 be used in populating the result:

   i._4 _4
15 14 13 12
11 10  9  8
 7  6  5  4
 3  2  1  0

But I guess the rule would be that items from Y in X$Y are arranged according to the sign of the final element of X (remember to ravel Y if it's rank 2 or higher and you want to reshape it as a list).

moon-chilled commented 2 years ago

I don't understand the significance of the signs of the elements of X other than the last. 'I expect that the index order of i._4 _4 be used in populating the result' does not illuminate; I don't see how to get from i._4 _4 to your expected result. If their signs are not significant, then I think this needs to be re-thought.

You say that $ should behave analogously to {.. Every element of the left argument to {. corresponds to one axis of the right argument. Which elements of the left argument to $ correspond to which axes of the right argument?

The result of $ has shape x,1}.$y. This seems to suggest a model in which the leading axis of y is rubbed out and replaced with the final element of x, the trailing axes are left in place, and the additional leading axes are tacked on. Only one of these statements makes any sense at all; the remainder do not, because the cells of y are extended cyclically. The signs of the last p elements of x at least should be significant, for the smallest p st 0=(#y)|*/(-p){.x (or #x if there is no such p). It would be nice if the remaining elements of x could be significant too.

One solution, which I find not insensible despite its simplicity, is to simply reverse along negative axes.

rdm commented 2 years ago

Right... there's several differences between $ and {.

One is that $ repeats items where {. uses fills when the left argument asks for a result larger than the right argument.

Another difference is that when $ contains multiple elements it will add dimensions where {. works downward from the highest dimension of the right argument.

...

Anyways, here's a model of the mechanism I think we should have for dyadic $:

reshape=: {{
   ((#y)|i.x){y
}}

Or, if you prefer tacit notation:

reshape=: ] {~ #@] | i.@[

moon-chilled commented 2 years ago

That is different from what you originally proposed, and it is the same as my suggestion to reverse along negated axes. I'm not making a value judgement, just pointing it out in case you missed it.

   4 4$(*/4 4)$&.|.'abc'
cabc
abca
bcab
cabc
   (3|i._4 4){'abc'
abca
cabc
bcab
abca
   |.4 4$'abc'
abca
cabc
bcab
abca
   (3|i.4 _4){'abc'
acba
bacb
cbac
acba
   |."1]4 4$'abc'
acba
bacb
cbac
acba
   (3|i._4 _4){'abc'
acba
cbac
bacb
acba
   |."1|.4 4$'abc'
acba
cbac
bacb
acba
rdm commented 2 years ago

Oops, you are right. I wasn't paying enough attention when I wrote that model.

It might actually be better than what I was originally thinking, but you were correct -- the final item in x has special significance. I can't think of any way to avoid that and achieve what I was originally thinking of.

Or the model for what I was originally thinking of would be

reshape=: {{
   ((#y)|i.x){|.^:(0>{:x) y
}}

Thanks.