Skip to content

Correspondence

Vector 14:4, page 9

APL community programming techniques

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

A False Simplification of atop?

The final sentence of J-ottings 16 (see page 48 in this issue), viz. ".. a thorough understanding of with, atop and hook is a major step to confidence in handling J" was written before I read Nick Cox’s letter in Vector 14.2, and so it is clear that we share at least a broad point of view. However, I want to point out the false simplifications inherent in the transliteration of J symbols into everyday words.

Mr. Cox suggests thinking of atop as "applied to" or "after". To me the ordinary processes of taking logs in order to multiply can be articulated as "addition after taking logs" or "addition applied to logs", yet this is precisely the situation in which one must not use atop. (see J-ottings 16 for details). Also Mr. Cox talks about a monadic hook, yet the whole point about any composition is that a new verb is defined independently of the data. A hook can be applied monadically, but in itself it is neither monadic nor dyadic. The rationale for a notation such as J, or for that matter APL, has always seemed to me to be to eliminate the very sort of ambiguities and uncertainties which Mr. Cox appears to be recommending!

Calculating Medians for Nested Arrays

Alan Sykes and Tom Stroud in "APL and Nested Arrays — A Dream for Statistical Computation" (Vector 14 No 2, pp 58–70) provide excellent demonstrations of the versatility of applying APL in the context of imputation. I would like to suggest that matters are even simpler than they suggest.

For example in the final section "Calculating Medians", although median is not a scalar function (which is what I meant by "not dimensionally extendible") this does not preclude its extension using each:

      R←MEDIAN X
[1] R←∆MEDIAN¨⊂[1]X←1/X

      R←∆MEDIAN X
[1] R←0.5×+/X[⌈0.5×0 1+⍴X←X[⍋X]]

      MEDIAN D←1,[1.5]8 9 11 13 16 18 6 4 20 25
1 12

Then, given the data structures which Alan and Tom use, in which Y is defined as shown below, their imputed means IMEDIAN are given by

      Y←(,10)(10 14)(,14)(16 14)(,16)(,15)(,20)(,4)(,18)(,22)

      R←NVTOMAT V
[1] R←⊃(⌈/,⊃¨⍴¨V)⍴V

      MEDIAN¨NVTOMAT¨⊂[1]D,Y
 1 12  15.5 14.5

One minor irritation in current APL life is the minor divergences between Dyalog and IBM APL, the latter of which requires the third character of the definition of NVTOMAT to be ⊃ as opposed to ↑ in Dyalog.

Sorites — J vs Prolog

I was delighted to see Norman Thomson’s J-ottings 15 appear in Vector Vol. 14, No. 3. You may be interested to know how I came to set Norman off on this particular trail. I wanted to see if I could incorporate within a computer program the transformation rules used when analysing any piece of symbolic logic (e.g. "not not A" is equivalent to "A"; "B implies A" is equivalent to "A or not B"; hence "[not B] implies A" is equivalent to "A or B", where "or" is the inclusive or) but I also wished to determine how well J stood up to another language on its own ground.

By its very name, Prolog seemed the natural language choice and I did produce a long, convoluted Prolog program of about 140 lines using the usual recursive Prolog techniques — but I found that I could reproduce the same results with just a few lines of J script.

Sorites are normally solved by using rules to eliminate propositions which appear in two of the given premises (e.g. if "A implies B" and "B implies C", then "A implies C"). Norman quickly extended my J results to produce all the valid implications from the sorites, not just the one left by this elimination process.

The outcome of our correspondence was J-ottings 15.

I hope that others have found this an entrancing by-road of J.

E.A.Clough

On Niven Numbers

On first reading Vector Vol. 14.2 I was attracted by one particular article, for three reasons: its Title, the first APL function and the Tables of timing comparisons.

  • The Title — I did not know about Niven numbers.
  • The function NIVEN1 of 4 lines with a missing closing parenthesis. Is it a copying error? David would say this is 20% error in 5 parentheses.
  • Comparison tables taking up more space than the functions!

In my opinion, differences of 2-3% are not significant and do not justify a choice of one coding over another. There are plenty of parameters which affect such cases and the ratios are not proportional.

  • the microprocessor (Motorola, Intel, Pentium …) + their MHz
  • the mathematical co-processor, if there is one
  • the operating system (mono or multi-tasking or TSO)
  • the interpreter (Dyalog APL, APL 2000, IBM APL2 family …)
  • the available memory (maybe swapping)
  • the memory management system (WS FULL)

etc., can be deemed to have an effect of +/- 5% on the performance of the code. On the other hand, a yield of a 25th begins to be interesting.

The author of the article, Joseph De Kerf, asks for:

"an algorithm which drastically improves this performance"

  • I have not, unfortunately, found such an algorithm.
  • I have, fortunately, at my disposal a programming language which allows even me to improve the performance but to achieve this I have had to develop variations and a new approach to NIVEN.

How? You will find the appropriate instructions and examples in the Technical Correspondence of this issue. The code is available on the Vector Web site.

Before placing the final full stop in my letter, I received Vector 14.3 with David Piper’s propositions. I agree with him completely on some points but certainly not with all his assertions.

Use of single character names!

Functions and variables must be understandable, but …

  • APL is of its nature concise (no key words in the standard language); each primitive is limited to an ideogram
  • In some applications the number of local variables may be important (10 letter variables take up space!)*
  • I am persuaded that in the UK, as in Switzerland, the first lesson in formal algebra is:
    A + B = C but certainly not: Asparagus + Banana = Chocolate

Multiple assignments on a single line. Why not?

  • It is necessary to pay attention to large volumes of data but also to think of each line as independent, allowing the operating system to take control between instructions. (Elapsed time?)
  • It is also necessary to think of the Vector Production team. (Economising on paper?)

Complex path analysis — Fighting dirty!

There is not 75% branching but 3 conditional GOTOs on 4 lines. In other words 3 simple conditions among 20 primitives.

While NIVEND also has 3 GOTOs spread over 11 lines, one to a label which does not exist! (This is an absurd example: full of names hiding the logic of the whole.) On the other hand, David does not mention which interpreter is being used.

My Conclusion

The search for a good performance in APL must not be about time* at all costs but an alliance of:

"APL logic + code + simplicity + time"

And, as a complement, trying to extract a positive message, it remains only for me to propose that you look at some of the possible versions of NIVEN under Technical Correspondence.

* Writing and typesetting also take time.

Claude Henriod

Y2K and Publicising APL

In Vector Vol.14 No.2 October 1997, Anne D. Wilson asked what the next panic problem would be. According to R.L. Glass in his article ‘The next date crisis’ (ACM, January 1997) this will be the Unix machine in the year 2035; the clock will ask for the not available next bit. (By the way, I was planning and preparing an article on ‘Dates’ after Bob Brown’s letter, but in spite of the fact that I’m quite familiar with this material the hurdles had easily been underestimated. Moreover, I agree with David Piper, that the code to be published should be more than OK, so altogether I definitely need more time.) But also the change from the native currencies in Europe to the Euro next year will give panic problem related headaches in the IT-industry.

Re the Editorial in Vector Vol.14 No.3, I would like to remark that it might be true that in general APL-ers are preaching to their own parish. Every mature APL-er however has an easy opportunity to write in other (general) papers or magazines. A few years ago I promised myself to respond to articles in such papers when the subject did fit well in an APL (or J or K) context. This has resulted in some articles on APL in ‘Computable’, a Dutch weekly, some being a half to an entire page (about A3), most of them with a technical touch, algorithms and code or pictures.

The titles I submitted included (translated): The future lies with Symbolic Languages (on APL), Use APL when it comes to Inversion (on databases), Programming without Calls (on Object Orientation), Math doesn’t hurt (on Functional Programming & Interpreters) and Leap year — horror scene? (on miscellaneous date problems).

Not a single one was ever refused. They usually will be refused when the tendency is too promotive, or when vendors try to sneak in. Just write informatively. If I can do it, everybody can.

For some articles I even got responses from interested novices (mostly for J) and I could direct them to the appropriate vendors. Of course, nobody knows the final results, it’s just a matter of ‘be good, tell it, never look behind’. Above all it should be fun.

Nevertheless, the best way to promote APL & Cousins remains in providing reliable commercial applications in a shorter time. If APL is your tool you can do it.

Abysmal Prrof Reading Standards

I am writing to complain about the abysmal standard of proof-reading which is persistently applied at VECTOR. Every time I send in my gems of code in order to rant against someone else’s crazy ideas or bad coding style or to enlighten your readership with some of my own the proof-reader fails to correct even the most obvious of my errors. I shall be sending back my Blue Peter badge in protest. You won’t be hearing from me again.

Exemplary Code!

Genuflections are due to David Piper for gracing us once again with such an exemplary piece of code. Imagine my distress when I discovered that the page containing the definition of again was missing from my copy of VECTOR. I feel sure that David has come up with something really special here so I should like to attempt to reconstruct it.

To an untrained eye it might at first seem that again is a variable. Now we can reasonably assume that the intention of the final branch in each function is to return to the line labelled next:. So if again is a variable it must take next’s value. Ah, but this is 5 in the thoughtfully decommented version of NIVEND but 4 in NIVENE. Now we know that David would not stoop to changing it without making the change quite explicit, so again cannot be a variable. What about a niladic function? Something like:

∇ r←again
⍝ generalised branch back destination function
 r←next
∇

I can’t really see David doing this as there is a hidden dependency between again and any function that calls it. How about?:

∇ r←again
⍝ generalised branch back destination function
 r←¯5+⊃1↓⎕lc
∇

This is much better because it no longer requires the target label to have a fixed name. Though it’s unfortunate if you need to branch back by anything other than 5 lines. This must be it!:

∇ r←again;z
⍝ generalised branch back destination function
⍝ lines in caller containing colon
 r←r/⍨':'∨.=⍨r←⎕cr⊃1↓⎕si
⍝ up to but excluding first colon in each line
 r←(⍴z)⍴(,z←z∘.≥⍳⌈/z←+/z)\(,z←∧\r≠':')/,r
⍝ evaluate labels selecting latest before current line
r←1⌈⌈/z/⍨(⊃1↓⎕lc)>z←⍎'0',,' ',r/⍨1=⎕nc r
∇

David, I am amazed. This is a masterpiece. I congratulate you. Only three concise well documented lines of code to determine whither the calling function should branch back. I particularly admire the way you have avoided the slavish following of your own arbitrary rules regarding identifier length and multiple assignment so that the standard algorithms (the long words of APL) shine through. Also the…

What? an error? Excuse me, the fool sitting next to me is rambling about again’s being a coding error. No, look, David tested his code, he even ran timings on it, a hundred thousand iterations …

Phil Last

Re APL Null Vector Vol 14 No 3

Here is your answer in words. When a scalar is combined with an array the resultant shape is nearly always the array shape. This is true for most of the arithmetic operations, e.g. = + × etc.

A reduction over an empty vector is always a ‘fringe’ condition and will try to return the identity of the primitive. Thus ‘or’ reduce returns zero, ‘and’ reduce returns one, times reduce returns one, plus reduce returns zero. Things like divide reduce are up against the fact that divide is not symmetric.

Now 2 ‘and’.= 0/ numeric vector first does the =, resulting in an empty vector, and then (second) does ‘and’ reduce, giving one. Using character arguments doesn’t change the result. It is important to remember the order of an inner product.

Primitives like epsilon or underscore epsilon don’t follow this easily, with epsilon returning a shape dependent on its left argument, epsilon underscore returning a shape dependent on its right argument. Again if you think what these primitives are meant to do both responses seem normal.

The question of an empty left argument with epsilon underscore is a result with right argument shape, and an empty array is (arguably) an element at every position of the right argument.

R.G. Selfridge
University of Florida