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
