Skip to content

The Hidden Variable Approach?

Vector 13:2, page 27

programming techniques education

Transcribed from the printed issue; not yet reviewed. Read it in the PDF of the issue, page 27

In J-ottings 8 Norman Thomson provided a different view of the uniform partition function. The approach scales up a division of (0,1) to the width of the given interval and moves it to the correct starting point. Writing Norman’s function a little differently, but assuming the same syntax "n sample a,b" for a partition of the interval (a,b) into n sub-divisions:

start_point_a =. {.@]                  NB. "a" in n sample a,b

indices =. i.@ >:                      NB. 0 1 2 3 4 5 ... n
sample_01 =. %~ indices                NB. 0, 1/n, 2/n, 3/n, ..., 1
n_width =. -/                          NB. a - b
scaled_sample =.( * sample_01)~ n_width NB. (a-b)* (0, 1/n, 2/n, ..., 1)
sample =. start_point_a - scaled_sample NB. a + (b-a)*(0, 1/n, 2/n, ..., 1)

The fixed form of sample is {.@] - ((* (%~ i.@>:))~ -/) and unfortunately has two more characters than Norman’s function, but it has only one reference to ]. On my machine it ran marginally faster for small samples, and marginally slower for larger samples.

It is a novel and an exhilarating experience to write a function like this, but note what has to be remembered:

  1. functions start_point_a and scaled_sample must have the same dyadic syntax as sample to fit the final fork
  2. indices is monadic, BECAUSE it will be used as second verb in the monadic hook sample_01
  3. sample_01 is monadic because it is used in the hook scaled_sample
  4. scaled_sample is a dyadic hook and n_width will be applied monadically.

I think the point I was trying to make was that any pupil in junior high school will be able to see how a + ((b-a)%n )* indices or a + (b-a)* indices%n works. They might have more trouble with the hidden variable approach or they may enjoy it, but their teachers will probably have a pink fit just thinking about it.

The "go-get-the-variable" approach is bound to have repetitions, because with tacit definition there is nowhere to store data. Incidentally, if one notes that the sample points are given by ((1 - sample_01) * a) + sample_01 * b, then we have a couple more symbols in (+/ .* (-. ,: +)@(%~ i.@>:))~ and 30% slower execution time, but no square brackets at all. The original {.@] + (({:@] - {.@] )% [ ) */ (i.@>:@[ ) with the most symbols and [ and ] references is slowest of all for small samples, but faster than all of them on my machine when n is large.

Execution times:

   n      T        R        S        M
 113   0.0297   0.0307   0.0374   0.0346
 913   0.0758   0.0692   0.0697   0.0984
3917   0.256    0.2224   0.2126   0.3405
9919   0.6124   0.5223   0.4455   0.8327

where:

T =.{.@] - ((* (%~ i.@>:))~ -/)
R =.{.@] + i.@>:@[ % (% -/@-)
S =.{.@] + (({:@] - {.@]) % [) */ (i.@>:@[)
M =.(+/ .* (-. ,: +)@(%~ i.@>:))~