sourcelibs/Kit/src/Kit.xtl

1⍝│ Kit: the experiment kit's data sets, each with a known structure and 2⍝│ made from its own seed: flat (Gaussian clusters), directional 3⍝│ (classes that differ by direction, not length) and hierarchical (a 4⍝│ tree, its distances along the tree, a class per branch, and a plain 5⍝│ layout of it in the plane); and the seeded numbers they are made of. 6⍝│ Import it with an alias of your choice: "kt:" u_se< "Kit". 7⍝│ Put libs/Kit/src on XETAL_PATH ("just path"); the reference is libs/Kit/docs. 8⍝│ Names with l: are exported; those under h: are private to this file. 9⍝│ 10⍝│ A data set is (X, y): X a matrix, one point per row; y its labels, 11⍝│ 1 to k. Every set is a function of its seed and its sizes alone (not 12⍝│ of the run's seed, nor of what was drawn before it), so two demos 13⍝│ asking for the same set get the same numbers: the seed is a whole 14⍝│ number, and the generator is Park and Miller's (1988) multiplier 15⍝│ 16807 modulo 2^31 - 1, written out here until X_eTaL-libraries' 16⍝│ Random takes a seed of its own (docs/xetal-libraries-asks.md, GL8). 17⍝│ The comparisons this repository makes are between geometries on the 18⍝│ same data: what these functions give is held equal across them. 19 20"mf:" u̲se< "Manifold" 21"gr:" u̲se< "Graphs" 22 23⍝━━ Seeded numbers 24 25⍝│ u̲niform (seed, n): n Floats in [0, 1), each a function of the 26⍝│ seed and its place: the Park-Miller sequence x -> 16807 x mod 27⍝│ (2^31 - 1) started from 1 + |seed| mod (2^31 - 2) (so seed 0 is a 28⍝│ seed like any other and no seed is the sequence's fixed point 0), 29⍝│ divided by 2^31 - 1. The same seed gives the same numbers in any 30⍝│ run. 31⍝│ >> "kt:" u_se< "Kit" 32⍝│ >> kt:u_niform (42, 3) 33⍝│ 0.00033653387815530127 0.6561248901561484 0.4910288543864288 34ˡu̲niform ← { (seed, n) → 35 m ← 2147483647 36 start ← 1 + (a̲bs seed) m̲od m − 1 37 (v, _) ← n '{ (v, x) → y ← (16807 × x) m̲od m◆ (v c̲at y, y) } p̲ower (0 r̲eshape 0, start) 38 (f̲loat v) ÷ f̲loat m 39} 40 41⍝│ n̲ormal (seed, n): n Floats from the standard normal distribution 42⍝│ (mean 0, standard deviation 1), by Box and Muller from 2n uniform 43⍝│ numbers of the seed. 44⍝│ >> "kt:" u_se< "Kit" 45⍝│ >> kt:n_ormal (42, 2) 46⍝│ -0.025904525013204074 -0.2561352551643429 47ˡn̲ormal ← { (seed, n) → 48 u ← ˡu̲niform (seed, 2 × n) 49 a ← n t̲ake u 50 b ← n d̲rop u 51 (s̲qrt -2.0 × l̲og 1.0 − a) × c̲os 6.283185307179586 × b 52} 53 54⍝│ n̲ormals (seed, rows, cols): a rows by cols matrix of standard 55⍝│ normal numbers of the seed. 56ʰn̲ormals ← { (seed, rows, cols) → (rows c̲at cols) r̲eshape ˡn̲ormal (seed, rows × cols) } 57 58⍝━━ Flat clusters 59 60⍝│ f̲lat (seed, k, n, d, spread): k Gaussian clusters of n points 61⍝│ each in d dimensions: the k centers are standard normal numbers of 62⍝│ the seed scaled by 4 (so clusters sit a few units apart), and each 63⍝│ point is its center plus spread times a standard normal vector; 64⍝│ (X, y), X of k n rows and y the cluster of each row, 1 to k, in 65⍝│ order. The structure is flat: straight-line distance is the right 66⍝│ one, and a point's nearest neighbors are mostly its own cluster 67⍝│ when spread is well under the centers' spacing. 68⍝│ >> "kt:" u_se< "Kit" 69⍝│ >> (X, y) := kt:f_lat (1, 2, 2, 2, 0.1) 70⍝│ >> y 71⍝│ 1 1 2 2 72⍝│ >> s_hape X 73⍝│ 4 2 74ˡf̲lat ← { (seed, k, n, d, spread) → 75 C ← 4.0 × ʰn̲ormals (seed, k, d) 76 N ← ʰn̲ormals (seed + 1, k × n, d) 77 y ← n ʰe̲ach r̲ange k 78 X ← ((f̲loat spread) × N) + y s̲elect C 79 (X, y) 80} 81 82⍝│ n e̲ach v: every item of v repeated n times, in order (a general 83⍝│ word, written out until GL2 lands). 84ʰe̲ach ← { n v → r̲avel o̲\ (n c̲at t̲ally v) r̲eshape v } 85 86⍝━━ Directions 87 88⍝│ d̲irections (seed, k, n, cone): k classes of n points in three 89⍝│ dimensions that differ by direction and not by length: each class 90⍝│ has a direction (a seeded standard normal vector put onto the unit 91⍝│ sphere) and each point is that direction plus cone times a 92⍝│ standard normal vector, put back onto the sphere, then scaled by a 93⍝│ length drawn between 0.5 and 2 (uniform), so the lengths carry 94⍝│ nothing about the class; (X, y). The structure is directional: the 95⍝│ angle between points is the right distance, and their straight-line 96⍝│ distance mixes in the lengths. 97⍝│ >> "kt:" u_se< "Kit" 98⍝│ >> (X, y) := kt:d_irections (7, 2, 2, 0.1) 99⍝│ >> y 100⍝│ 1 1 2 2 101⍝│ >> s_hape X 102⍝│ 4 3 103ˡd̲irections ← { (seed, k, n, cone) → 104 D ← ᵐᶠs̲phereProject ʰn̲ormals (seed, k, 3) 105 N ← ʰn̲ormals (seed + 1, k × n, 3) 106 y ← n ʰe̲ach r̲ange k 107 U ← ᵐᶠs̲phereProject ((f̲loat cone) × N) + y s̲elect D 108 lengths ← 0.5 + 1.5 × ˡu̲niform (seed + 2, k × n) 109 (lengths ʰs̲caleRows U, y) 110} 111 112⍝│ s v s̲caleRows M: each row of M scaled by the matching item of s. 113ʰs̲caleRows ← { s M → M × s 'l̲eft t̲able o̲ffsets 2 s̲elect s̲hape M } 114 115⍝━━ A tree 116 117⍝│ t̲ree (depth, branching): the edges of a rooted tree in which 118⍝│ every node but the leaves has branching children and every leaf 119⍝│ is depth edges from the root: node 1 is the root and the nodes 120⍝│ are numbered level by level, so node i's children are the nodes 121⍝│ branching (i - 1) + 2 up to branching i + 1. The edges as Graphs 122⍝│ takes them: two rows, from (the parent) over to (the child). Depth 123⍝│ 4 and branching 2 give 31 nodes and 30 edges. 124⍝│ >> "kt:" u_se< "Kit" 125⍝│ >> kt:t_ree (2, 2) 126⍝│ 1 1 2 2 3 3 127⍝│ 2 3 4 5 6 7 128ˡt̲ree ← { (depth, branching) → 129 n ← ʰn̲odes (depth, branching) 130 child ← 1 d̲rop r̲ange n 131 parent ← 1 + (child − 2) d̲iv branching 132 (2 c̲at n − 1) r̲eshape parent c̲at child 133} 134 135⍝│ The number of nodes of the tree: 1 + b + b^2 + ... + b^depth. 136ʰn̲odes ← { (depth, branching) → '+ r̲/ branching ^ (r̲ange depth + 1) − 1 } 137 138⍝│ t̲reeDistances (depth, branching): the distance between every two 139⍝│ nodes of the tree along it (the number of edges on the one path 140⍝│ between them), by Graphs' shortest paths over the tree's edges 141⍝│ taken both ways: an n by n matrix of Floats, 0 on the diagonal, 142⍝│ 2 depth at most (leaf to leaf through the root). 143⍝│ >> "kt:" u_se< "Kit" 144⍝│ >> kt:t_reeDistances (1, 2) 145⍝│ 0.0 1.0 1.0 146⍝│ 1.0 0.0 2.0 147⍝│ 1.0 2.0 0.0 148ˡt̲reeDistances ← { (depth, branching) → 149 n ← ʰn̲odes (depth, branching) 150 e ← ˡt̲ree (depth, branching) 151 w ← n ᵍʳw̲eighted e c̲at (n − 1) r̲eshape 1 152 ᵍʳs̲hortest ᵍʳu̲ndirected w 153} 154 155⍝│ t̲reeClasses (depth, branching): the class of each node, its 156⍝│ branch: the child of the root it descends from, 1 to branching; 157⍝│ the root itself, which is under no branch, is given class 1 (and 158⍝│ a classifier is excused it: it is alone). So the hierarchical 159⍝│ set's labels, one per node. 160⍝│ >> "kt:" u_se< "Kit" 161⍝│ >> kt:t_reeClasses (2, 2) 162⍝│ 1 1 2 1 1 2 2 163ˡt̲reeClasses ← { (depth, branching) → 164 n ← ʰn̲odes (depth, branching) 165 parent ← f̲irst ˡt̲ree (depth, branching) 166 up ← depth '{ v → '{ c → parent ʰu̲p c } e̲ach v } p̲ower r̲ange n ⍝ each node's ancestor just under the root (the root stays) 167 1 m̲ax up − 1 168} 169 170⍝│ parent u̲p c: the parent of node c, unless that is the root (or c 171⍝│ is), in which case c: one step up the tree that stops under the root. 172ʰu̲p ← { parent c → c = 1 ? 1◆ p ← (c − 1) s̲elect parent◆ p = 1 ? c◆ p } 173 174⍝│ t̲reeLayout (depth, branching): a plain picture of the tree in 175⍝│ the plane, one row (x, y) per node: the root at the origin, each 176⍝│ level a circle of radius its depth, the nodes of a level spread 177⍝│ evenly round it in their order, so that each subtree is a wedge 178⍝│ (the two children of the root at the top and the bottom, their x 179⍝│ cos of a quarter turn, 0 up to the machine's rounding). It is a 180⍝│ layout, not an embedding that keeps the tree's distances: 181⍝│ the straight-line distance between two nodes of this picture is a 182⍝│ poor copy of their distance along the tree (two leaves of 183⍝│ neighboring branches are near in the picture and 2 depth apart 184⍝│ in the tree), which is what the baseline measures. 185⍝│ >> "kt:" u_se< "Kit" 186⍝│ >> kt:t_reeLayout (1, 2) 187⍝│ 0.0 0.0 188⍝│ 0.00000000000000006123233995736766 1.0 189⍝│ -0.00000000000000018369701987210297 -1.0 190ˡt̲reeLayout ← { (depth, branching) → 191 n ← ʰn̲odes (depth, branching) 192 level ← 1 s̲elect ˡt̲reeDistances (depth, branching) ⍝ each node's distance from the root 193 before ← '{ L → '+ r̲/ 0 c̲at branching ^ (r̲ange L) − 1 } e̲ach f̲loor level ⍝ nodes on the levels above 194 on ← f̲loat branching ^ f̲loor level ⍝ nodes on the node's level 195 pos ← (f̲loat (r̲ange n) − before) − 0.5 ⍝ its place round the circle, from 0.5 196 angle ← 6.283185307179586 × pos ÷ on 197 o̲\ (2 c̲at n) r̲eshape (0.0 + level × c̲os angle) c̲at 0.0 + level × s̲in angle 198}