Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

repetitive verb applications and store results in vector

Tags:

j

Suppose I have a verb v, for example, defined as v=.>:@*:, and I want apply v to some initial value n times, and store all intermediate results in a vector, like the following for n=4 and the initial value 2

2 5 26 677 458330

I am not sure how to "extend" the vector while applying the verb, even though I know one can probably use ^: to do application n times.

Please help.

like image 365
Dick Avatar asked Dec 25 '22 19:12

Dick


2 Answers

J has a built-in operator for this and related operations: ^: (read ''power''). The particular variety of power you're looking for is when its right-hand argument is a boxed number (or numbers):

   v^:(<n) initial_value

as in/:

   >:@*:^:(<1+4) 2
2 5 26 677 458330

To make this a reusable verb (abstraction over n and the initial value):

   vv =: >:@*:@]^:(<@>:@[)
   4 vv 2
2 5 26 677 458330

To make this a reusable adverb (abstracted over n, the initial value, and v):

   V =: (@]) (^:(<@>:@[))
   4 >:@*: V 2
2 5 26 677 458330

Note that ^: also has other flavors. For example, if its right-hand argument is an unboxed number (or numbers), it just applies the function N times and produces the final value, rather than building up a vector of intermediate values.

Or, if its right-hand argument is infinite, it will apply the function to its fixed point. Or, combining these two observations, if its right-hand argument is boxed and infinite, it applies the function to its fixed point, building a vector of intermediate values along the way. And plenty of other neat tricks.


PS: Composing the function >: with the function *: using @ as in >:@*: will correctly produce the input squared plus one.

However, since @ is defined to act like an assembly line, passing each output of *: to >: individually, the latter verb (increment) will be invoked #y times. You could get the same result, more efficiently, using @: ("atop") in place of @ ("at").

As a composing operator, @: is more like a hopper than an assembly line: it waits for *: finish processing completely, collects all its results together, and passes them to >: in one go.

Given J's array oriented nature, the rule of thumb is "think big". That is, let each primitive see as much data as possible, and let the interpreter manage the details. While you're learning J, it might be worth adopting "use @: instead of @" as a blanket rule, until you get a handle of the nuances.

like image 180
Dan Bron Avatar answered Jan 29 '23 03:01

Dan Bron


What I usually do for this is apply v to the tail (or head) of the list and append the result to the list:

v1 =: 3 :'y , v {: y'

v1 1
1 2

v1 1 2
1 2 5

(v1^:5) 1
1 2 5 26 677 458330

There are many variations of this you can use, depending on the desired efficiency, the structure of your data, etc.

like image 34
Eelvex Avatar answered Jan 29 '23 03:01

Eelvex