This isn't to do with forks vs trains per se. It is about J working better
on (big) chunks rather than small ones. Using & or @ rather than &: or @:
causes the verb to the left to operate on chunks that are a size determined
by the rank of the verb to the right. Using @: or &: causes the verb to the
right to finish processing and provide the entire array to the verb on the
left.

([: *: >:) is equivalent to *:@:>:
In this case the answer is the same as for *:@>: but the processing path is
different.

Both >: and *: are rank 0
   >: b. 0

0 0 0

   *: b. 0

0 0 0


So *:@>: will process each atom of the argument separately whereas *:@:>:
will finish incrementing all the atoms in the argument and then give the
entire result to square (*:) to process. This might help visualise what is
going on:


<@:*:@>:  0 1 2 3 4 5

+-+-+-+--+--+

|1|4|9|16|25|

+-+-+-+--+--+

<@:*:@:>:  0 1 2 3 4 5

+-----------+

|1 4 9 16 25|

+-----------+


Looking at the timing differences in sentences below you can see that they
key is that *: is operating on the entire array.

6!:2 '(+/@:(*:&>:&i.))"0 (i.9999)'

13.55

6!:2 '(+/@:(*:&:>:&:i.))"0 (i.9999)'

0.162699

6!:2 '(+/@:(*:@:>:@:i.))"0 (i.9999)'

0.169901

6!:2 '(+/@:(*:@>:@i.))"0 (i.9999)'

13.4185

6!:2 '(+/@:(*:@:>:@i.))"0 (i.9999)'

0.156401

6!:2 '(+/@:(*:@>:@:i.))"0 (i.9999)'

13.49


Note that there appears to be no performance benefit between >:@i. and
>:@:i. because the monadic rank of i. is 1
   i. b. 0

1 _ _


The rank of the argument given to i. is already 1 or less, so >: is being
given the whole result from i. already.

Hope that helps

On Thu, Jun 23, 2016 at 12:10 PM, Moon S <[email protected]> wrote:

> I was searching integer solutions (k,m) for
>    1^2 + 2^2 + ... + k^2 = m^2
> and I found that one expression runs much faster than the other:
>
>    (#~(0=1|[:%:+/@:([:*:1+i.))"0) 2+i.9999
> 24
>    (#~(0=1|[:%:+/@:(*:&>:&i.))"0) 2+i.9999
> 24
>
> The first one is ~100 times faster, and moreover, the expression with '+/'
> is faster, then without it!
>
>    (3) 6!:2 '(+/@:([:*:1+i.))"0 (i.9999)'         NB. with +/ and fork
> 0.143744
>    (3) 6!:2 '(+/@:(*:&>:&i.))"0 (i.9999)'        NB. with +/ and train
> 13.4614
>
>    (3) 6!:2 '([:*:1+i.)"0 (i.9999)'      NB. without +/
> 0.608895
>    (3) 6!:2 '(*:&>:&i.)"0 (i.9999)'
> 14.0192
>
> As for '+/' I think the explanation is that no additional arrays are
> created, the sums are just computed on the fly.
> But the question remains, why the (equivalent) fork is so much faster than
> the train?
>
> Hm, changing the long train to a shorter one with a fork helps:
>    (3) 6!:2 '(*:&(1+i.))"0 (i.9999)'
> 0.62027
> So, what's the rule?
>
> ---
> Georgiy Pruss
> ----------------------------------------------------------------------
> For information about J forums see http://www.jsoftware.com/forums.htm
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to