Stencil and Co-dfns

Stencil() is the famous operator from Dyalog that enables writing image processing code in a convenient way. An example would be dilation.

  |dilation{/{,}(1+2× )} ⍝ ⍺ is the radius

The interpreter of Dyalog has a few special code that avoids consing caused by interpreting the left operand multiple times, if it is in one of the following forms:

  |   {}      {}      {,}      {}
  |{+/,}    {/,}    {/,}    {=/,}    {/,}  
  |{  +/,A×}    {  +/A×2}
  |{C<+/,A×}    {C<+/A×2}

Apparently, {⌈/,⍵} is not in it so that is the reason the above APL function would be implemented that way.

With Co-dfns, APL code is compile to C++ code before execution so consing should never be worried. However, current version of Co-dfns does not support stencil directly yet.

  |{¯2 ¯1 0 1 20 3¯2 ¯1 0 1 20 2}

This is similar to dilation but with radius fixed to 2, and the image is treated as a torus instead of clipping at edge.

Too sad you cannot see this image!
Figure 1.1 From left to right are original, with dilation , with erosion .

Actually, even without been compiled this version is a bit faster than the one uses stencil, which exceeded my expectation. The compiled version with CPU backend is much slower, apparently the plain C++ code lacks the magical optimization done by Dyalog interpreter. (Did I mentioned foreign function call cost?) I don't have GPU so if someone is able to test please help. The benchmark is tested on randomized array of shape 1500 1500.

  co-dfns cpu  → 9.9E¯1 |   0% ⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
  interpreted  → 5.1E¯2 | -95% ⎕⎕                                      
* stencil      → 7.9E¯2 | -92% ⎕⎕⎕


[dilation] Dilation (morphology). Wikipedia.

[Hui20] Towards Improvements to Stencil. Roger Hui.