APL Wiki logo: Difference between revisions

From APL Wiki
Jump to navigation Jump to search
Miraheze>Adám Brudzewsky
No edit summary
Miraheze>Adám Brudzewsky
No edit summary
Line 11: Line 11:
1 2 3 2 1
1 2 3 2 1
</source>
</source>
This page explains, step-by-step, how we generate our SVG logo, using the above expression<ref>[https://codegolf.stackexchange.com/users/78410/bubbler "Bubbler"], message [https://chat.stackexchange.com/transcript/message/52389201#52389201 "52389201"] in ''The Nineteenth Byte'' chat room. Stack Exchange network, 2019-10-31 23:57</ref> — an expression which happens to demonstrates quite a few APL features.
This page explains, step-by-step, how we generate our SVG logo, using the above expression<ref>[https://codegolf.stackexchange.com/users/78410/bubbler "Bubbler"], message [https://chat.stackexchange.com/transcript/message/52389201#52389201 "52389201"] in ''The Nineteenth Byte'' chat room. Stack Exchange network, 2019-10-31 23:57</ref>. This demonstrates quite a few APL features.


We will follow APL's evaluation from [[Evaluation order|right to left]].
We will follow APL's evaluation from [[Evaluation order|right to left]].
Line 138: Line 138:
1 2 3 2 1
1 2 3 2 1
</source>
</source>
And there it is!
Those are our radii! Let's save them:
<source lang=apl>
      r←⌊∘.+⍨.5×4!⍨⍳5
</source>
 
== Towards an SVG ==
=== Placing the circles ===
Now that we have our radii, we need to figure out where to put our circles. The horizontal pair-wise sum shows how much adjacent circles "reach out" towards each other. [[N-wise Reduce]] solves that. Here, <source lang=apl inline>/</source> is an operator which takes the plus function and applies it in-between the elements of each horizontal run of length ''N'' (the left argument) in the right argument:
<source lang=apl>
      2+/sizes
3  5  5 3
6  9  9 6
8 11 11 8
6  9  9 6
3  5  5 3
</source>
Since the circles line up on a grid, we need the maximum for each horizontal space, that is for each column. APL uses [[dyad]]ic <source lang=apl inline>a⌈b</source> as the [[maximum]] of ''a'' and ''b''. <source lang=apl inline>⌈⌿</source> is the columnar maximum-[[reduce|reduction]]:
<source lang=apl>
      ⌈⌿2+/sizes
8 11 11 8
</source>
But obviously, we can't let the circles touch, so we add 1. Finally, we prepend a 0 which is the offset of the first circle:
<source lang=apl>
      ⊢offsets←0,+\1+⌈⌿2+/sizes
0 9 21 33 42
</source>
<source lang=apl inline>⊢</source> is the [[identity]] function, which is just used here get the pass-though value from the assignment, as it would otherwise be hidden. (We call assignment ''shy''.)
 
<source lang=apl inline>⍴</source> is the [[shape]] and <source lang=apl inline>⍳</source> generates the [[index of|indices]] of an array of that size.
<source lang=apl>
      ⍴r
5 5
      ⊢indices←⍳⍴r
┌───┬───┬───┬───┬───┐
│0 0│0 1│0 2│0 3│0 4│
├───┼───┼───┼───┼───┤
│1 0│1 1│1 2│1 3│1 4│
├───┼───┼───┼───┼───┤
│2 0│2 1│2 2│2 3│2 4│
├───┼───┼───┼───┼───┤
│3 0│3 1│3 2│3 3│3 4│
├───┼───┼───┼───┼───┤
│4 0│4 1│4 2│4 3│4 4│
└───┴───┴───┴───┴───┘
</source>
Now we take each coordinate (i.e. each [[rank]] 0 cell) from that and use it to [[Squad index|index]] into the list (a [[rank]] 1 array) of offsets. The result is has shape…
<source lang=apl>
      ⍴xy←indices⌷⍤0 1⊢offsets
5 5 2
</source>
that is, it is a 3D array with 5 layers, 5 rows in each layer, and 2 columns in each row. Each row represents an <math>(x,y)</math> value. The first and last layers, which represents the leftmost and rightmost columns of the logo, are:
<source lang=apl>
      (1↑xy) (¯1↑xy)
┌────┬─────┐
│0  0│42  0│
│0  9│42  9│
│0 21│42 21│
│0 33│42 33│
│0 42│42 42│
└────┴─────┘
</source>
E.g. the second row in the first layer is <math>(x,y)=(0,9)</math>
 
<source lang=apl>
</source>
=== Making <code><circle/></code> tags ===
<source lang=apl>
</source>
 
<source lang=apl>
</source>
 
<source lang=apl>
</source>


== References ==
== References ==
<references />
<references />

Revision as of 14:43, 5 November 2019

APL Wiki logo

The APL Wiki logo consists of the following numeric matrix, where each number indicates a circle radius:

      ⎕IO←0
      ⌊∘.+⍨.5×4!⍨⍳5
1 2 3 2 1
2 4 5 4 2
3 5 6 5 3
2 4 5 4 2
1 2 3 2 1

This page explains, step-by-step, how we generate our SVG logo, using the above expression[1]. This demonstrates quite a few APL features.

We will follow APL's evaluation from right to left.

Counting

From 1 or from 0?

A computer console:

Whether to count from 0 or from 1 is an old disagreement among programmers. Many APLs let you choose whichever convention you want, but they tend to use 1 by default. To switch convention, we set the variable ⎕IO:

      ⎕IO←0

By the way, IO stands for Index Origin.

We can already now observe a couple of APL's characteristics…

No reserved words

The name ⎕IO begins with the special Quad character (a stylised console) which symbolises the computer system itself. APL has no reserved words. Rather, all built-in constants, variables, functions and operators have the prefix indicating that they are part of the system. Because of this, we call them quad names.

Assignments

  • Assignment is not done with = like in many other programming languages, but rather with which also indicates the direction of the assignment: Whatever is on the right gets put into the name on the left.

Generating indices

The function takes a number N and generates indices until is has made N indices. Since we set ⎕IO to 0, we count from 0 until right before N:

      ⍳5
0 1 2 3 4

How many subsets?

Consider a bag with four distinct items. If you stick your hand into the bag and pick two items out, how many different possibilities are there for which pair you get out? . APL can tell you this with the Binomial (!) function:

      2!4
6

Notice how APL uses traditional mathematical symbols in a generalised way. The traditional post-fix (after its argument) symbol is used with a syntax similar to how you'd normally use or Failed to parse (syntax error): {\displaystyle ×} . In fact, all APL functions can be used infix, like or prefix, like .

Anyway, how many sets of four could you pick? Obviously, only one; all the items:

      4!4
1

Automatic mapping

A really nice feature of APL is its array-orientation. For computations which are defined on single elements (scalar functions), mapping is implicit:

      0 1 2 3 4!4
1 4 6 4 1

(What's up with picking zero out of four items? Since all empty hands are equal, there is exactly one such set — the empty set.)

Order of evaluation

We want to generate the indices using Iota ()…

      ⍳5!4


That didn't work! This is because APL dispenses with traditional mathematics' confusing and inconsistent precedence order[2], replacing it with a simple right-to-left rule:

      (⍳5)!4
1 4 6 4 1

Swapping arguments

If the arguments of ! were swapped, we wouldn't need that parenthesis. Enter the operator (higher-order function) swap () which takes a dyadic function on its left and creates a new derived function which is identical to the original, but has swapped arguments:

      4!⍨⍳5
1 4 6 4 1

A number is a number

The next step is to halve everything:

      .5×4!⍨⍳5
0.5 2 3 2 0.5

Notice how we were dealing with integers until now, but then we multiply by a float (non-integer). In APL, you don't need to worry about numeric data type conversions. All numeric types get automatically promoted and demoted as needed. APL implementations will usually use the most compact internal representation.

Traditional mathematical symbols

Also notice that we use a proper multiplication symbol, Failed to parse (syntax error): {\displaystyle ×} , for multiplication. If traditional mathematics has a symbol for a concept APL includes then APL will use that symbol. Another example is Failed to parse (syntax error): {\displaystyle ÷} for division.

Tables

Remember the multiplication table from school?

      1 2 3 4 5∘.×1 2 3 4 5
1  2  3  4  5
2  4  6  8 10
3  6  9 12 15
4  8 12 16 20
5 10 15 20 25

Any function can be made into a table with the Outer Product:

      1 2 3 4 5∘.+1 2 3 4 5
2 3 4 5  6
3 4 5 6  7
4 5 6 7  8
5 6 7 8  9
6 7 8 9 10

Using an argument twice

It gets tedious to type the same argument twice. Enter the selfie operator which shares its symbol with the above-mentioned swap operator. There's no ambiguity here. Swap swaps the two arguments, while selfie uses a single argument twice:

      ∘.+⍨1 2 3 4 5
2 3 4 5  6
3 4 5 6  7
4 5 6 7  8
5 6 7 8  9
6 7 8 9 10

We'll use this in our logo expression:

      ∘.+⍨.5×4!⍨⍳5
1   2.5 3.5 2.5 1  
2.5 4   5   4   2.5
3.5 5   6   5   3.5
2.5 4   5   4   2.5
1   2.5 3.5 2.5 1

Rounding

The last step is to round these numbers down. Traditional mathematics writes floor as Failed to parse (syntax error): {\displaystyle ⌊x⌋} but APL is regular, so no function is denoted by two separated symbols. If the function takes a single argument, then the symbol will be on the left, so we write floor as ⌊x:

      ⌊∘.+⍨.5×4!⍨⍳5
1 2 3 2 1
2 4 5 4 2
3 5 6 5 3
2 4 5 4 2
1 2 3 2 1

Those are our radii! Let's save them:

      r←⌊∘.+⍨.5×4!⍨⍳5

Towards an SVG

Placing the circles

Now that we have our radii, we need to figure out where to put our circles. The horizontal pair-wise sum shows how much adjacent circles "reach out" towards each other. N-wise Reduce solves that. Here, / is an operator which takes the plus function and applies it in-between the elements of each horizontal run of length N (the left argument) in the right argument:

      2+/sizes
3  5  5 3
6  9  9 6
8 11 11 8
6  9  9 6
3  5  5 3

Since the circles line up on a grid, we need the maximum for each horizontal space, that is for each column. APL uses dyadic a⌈b as the maximum of a and b. ⌈⌿ is the columnar maximum-reduction:

      ⌈⌿2+/sizes
8 11 11 8

But obviously, we can't let the circles touch, so we add 1. Finally, we prepend a 0 which is the offset of the first circle:

      ⊢offsets←0,+\1+⌈⌿2+/sizes
0 9 21 33 42

is the identity function, which is just used here get the pass-though value from the assignment, as it would otherwise be hidden. (We call assignment shy.)

is the shape and generates the indices of an array of that size.

      ⍴r
5 5
      ⊢indices←⍳⍴r
┌───┬───┬───┬───┬───┐
│0 0│0 1│0 2│0 3│0 4│
├───┼───┼───┼───┼───┤
│1 0│1 1│1 2│1 3│1 4│
├───┼───┼───┼───┼───┤
│2 0│2 1│2 2│2 3│2 4│
├───┼───┼───┼───┼───┤
│3 0│3 1│3 2│3 3│3 4│
├───┼───┼───┼───┼───┤
│4 0│4 1│4 2│4 3│4 4│
└───┴───┴───┴───┴───┘

Now we take each coordinate (i.e. each rank 0 cell) from that and use it to index into the list (a rank 1 array) of offsets. The result is has shape…

      ⍴xy←indices⌷⍤0 1⊢offsets
5 5 2

that is, it is a 3D array with 5 layers, 5 rows in each layer, and 2 columns in each row. Each row represents an value. The first and last layers, which represents the leftmost and rightmost columns of the logo, are:

      (1↑xy) (¯1↑xy)
┌────┬─────┐
│0  0│42  0│
│0  9│42  9│
│0 21│42 21│
│0 33│42 33│
│0 42│42 42│
└────┴─────┘

E.g. the second row in the first layer is


Making <circle/> tags




References

  1. "Bubbler", message "52389201" in The Nineteenth Byte chat room. Stack Exchange network, 2019-10-31 23:57
  2. K.E. Iverson, Appendix A: Conventions Governing Order of Evaluation, Elementary Functions: An Algorithmic Treatment). Science Research Associates, 1966