sourcedemos/welcome/welcome.xtl
1⍝!/usr/bin/env xetal
2⍝│ Welcome: one small calculation on which a newcomer is shown how
3⍝│ these lessons work (the page steps through it, pictures it, writes
4⍝│ one of its sums out). It is the layer of the first lesson, LoRA
5⍝│ hello: a frozen table W of 4 rows and 4 columns with an adapter of
6⍝│ rank 1, written this time as a pipeline: the input x, then the
7⍝│ squeeze h = A x, then the spread u = B h, then the output
8⍝│ y = W x + s u. X_eTaL-ML's Flow runs the pipeline and can report
9⍝│ every stage's value, which is what a page steps through.
10
11"e:" u̲se< "Equations"
12"flow:" u̲se< "Flow"
13"lo:" u̲se< "LoRA"
14
15⍝━━ The layer
16
17⍝│ The frozen table W (16 made-up numbers, from a sine), the adapter's
18⍝│ two thin tables A and B, one input X, and the strength s (alpha is
19⍝│ 2, the rank is 1).
20W ← 4 4 r̲eshape s̲in 0.7 × f̲loat r̲ange 16
21A ← 1 4 r̲eshape 0.5 -0.5 1.0 0.25
22B ← 4 1 r̲eshape 1.0 0.0 -1.0 0.5
23X ← 1.0 2.0 3.0 4.0
24s ← 2.0 ˡᵒs̲caling 1
25
26⍝━━ The layer as a pipeline
27
28⍝│ Four stages, each a line: the data, then three equations. A stage
29⍝│ names its value after the $ sign, and a later stage may use it.
30y ← @ ᶠˡᵒʷp̲ipe< c#"
31 X ▹x
32▷ "h[k] | 1" ᵉe̲q< "sum j:=0..3 | A[k,j] * x[j]" ▹h
33▷ "u[i] | 4" ᵉe̲q< "sum k:=0..0 | B[i,k] * h[k]" ▹u
34▷ "y[i] | 4" ᵉe̲q< "(sum j:=0..3 | W[i,j] * x[j]) + s * u[i]""#
35y
36
37⍝━━ For the page
38
39⍝ The numbers of the three tables, row by row, for the pictures.
40r̲avel W
41r̲avel A
42r̲avel B
43⍝ Stage 2 written out: each number of A times the matching number of
44⍝ x, then their sum, which is h.
45X × r̲avel A
46'+ r̲/ X × r̲avel A
47⍝ The output if the last stage counted the spread-out list four times
48⍝ instead of twice (a strength of 4), for the sentence about a change:
49⍝ its first number.
501 t̲ake (W, A, B, 4.0 ˡᵒs̲caling 1) ˡᵒf̲orward X
ᶠˡᵒʷp̲ipe< expands to
({ @ →
x ← X
h ← "h[k] | 1" ᵉe̲q< "sum j:=0..3 | A[k,j] * x[j]"
u ← "u[i] | 4" ᵉe̲q< "sum k:=0..0 | B[i,k] * h[k]"
g1:stage ← "y[i] | 4" ᵉe̲q< "(sum j:=0..3 | W[i,j] * x[j]) + s * u[i]"
g1:stage
} @)ᵉe̲q< expands to
(({ @ →
g4:a̲t ← { A i → (1 + i) s̲elect r̲avel A }
g3:c̲heck ← { (A, name, k, from) e →
n ← k s̲elect s̲hape A
bad ← w̲here n̲ot r̲avel (0 ≤ e) ∧ e < n
0 = t̲ally bad ? e
"index" ⎕S̲IGNAL name c̲at " axis " c̲at (f̲ormat k) c̲at ": index " c̲at (f̲ormat (f̲irst bad) s̲elect r̲avel e) c̲at " is outside 0.." c̲at (f̲ormat n − 1) c̲at " (from " c̲at from c̲at ")"
}
g2:r̲ank ← { (A, name, q, ref) →
(t̲ally s̲hape A) = q ? A
"rank" ⎕S̲IGNAL ref c̲at " indexes " c̲at (f̲ormat q) c̲at " axes, but " c̲at name c̲at " has rank " c̲at f̲ormat t̲ally s̲hape A
}
g5:grid ← 1
g6:g̲rid ← { k → g5:grid r̲eshape (o̲ffsets k s̲elect g5:grid) 'l̲eft t̲able ('× r̲/ k d̲rop g5:grid) r̲eshape 0 }
g5:grid r̲eshape (({ @ →
g7:grid ← 1 c̲at ({ v → (0 ≤ v) ? v◆ "bad-equation" ⎕S̲IGNAL "sum's range runs low..high: 0..3" } (1 + 3 − 0))
g8:g̲rid ← { k → g7:grid r̲eshape (o̲ffsets k s̲elect g7:grid) 'l̲eft t̲able ('× r̲/ k d̲rop g7:grid) r̲eshape 0 }
'+ r̲/₂ g7:grid r̲eshape ((
((g2:r̲ank (A, "A", 2, "A[k,j]")) g4:a̲t ((
((A, "A", 2, "j") g3:c̲heck (0 + g8:g̲rid 2)) + (2 s̲elect s̲hape A) ×
((A, "A", 1, "k") g3:c̲heck (0 + g8:g̲rid 1))))) ×
((g2:r̲ank (x, "x", 1, "x[j]")) g4:a̲t (
((x, "x", 1, "j") g3:c̲heck (0 + g8:g̲rid 2))))))
} @))
} @))ᵉe̲q< expands to
(({ @ →
g11:a̲t ← { A i → (1 + i) s̲elect r̲avel A }
g10:c̲heck ← { (A, name, k, from) e →
n ← k s̲elect s̲hape A
bad ← w̲here n̲ot r̲avel (0 ≤ e) ∧ e < n
0 = t̲ally bad ? e
"index" ⎕S̲IGNAL name c̲at " axis " c̲at (f̲ormat k) c̲at ": index " c̲at (f̲ormat (f̲irst bad) s̲elect r̲avel e) c̲at " is outside 0.." c̲at (f̲ormat n − 1) c̲at " (from " c̲at from c̲at ")"
}
g9:r̲ank ← { (A, name, q, ref) →
(t̲ally s̲hape A) = q ? A
"rank" ⎕S̲IGNAL ref c̲at " indexes " c̲at (f̲ormat q) c̲at " axes, but " c̲at name c̲at " has rank " c̲at f̲ormat t̲ally s̲hape A
}
g12:grid ← 4
g13:g̲rid ← { k → g12:grid r̲eshape (o̲ffsets k s̲elect g12:grid) 'l̲eft t̲able ('× r̲/ k d̲rop g12:grid) r̲eshape 0 }
g12:grid r̲eshape (({ @ →
g14:grid ← 4 c̲at ({ v → (0 ≤ v) ? v◆ "bad-equation" ⎕S̲IGNAL "sum's range runs low..high: 0..0" } (1 + 0 − 0))
g15:g̲rid ← { k → g14:grid r̲eshape (o̲ffsets k s̲elect g14:grid) 'l̲eft t̲able ('× r̲/ k d̲rop g14:grid) r̲eshape 0 }
'+ r̲/₂ g14:grid r̲eshape ((
((g9:r̲ank (B, "B", 2, "B[i,k]")) g11:a̲t ((
((B, "B", 2, "k") g10:c̲heck (0 + g15:g̲rid 2)) + (2 s̲elect s̲hape B) ×
((B, "B", 1, "i") g10:c̲heck (0 + g15:g̲rid 1))))) ×
((g9:r̲ank (h, "h", 1, "h[k]")) g11:a̲t (
((h, "h", 1, "k") g10:c̲heck (0 + g15:g̲rid 2))))))
} @))
} @))ᵉe̲q< expands to
(({ @ →
g18:a̲t ← { A i → (1 + i) s̲elect r̲avel A }
g17:c̲heck ← { (A, name, k, from) e →
n ← k s̲elect s̲hape A
bad ← w̲here n̲ot r̲avel (0 ≤ e) ∧ e < n
0 = t̲ally bad ? e
"index" ⎕S̲IGNAL name c̲at " axis " c̲at (f̲ormat k) c̲at ": index " c̲at (f̲ormat (f̲irst bad) s̲elect r̲avel e) c̲at " is outside 0.." c̲at (f̲ormat n − 1) c̲at " (from " c̲at from c̲at ")"
}
g16:r̲ank ← { (A, name, q, ref) →
(t̲ally s̲hape A) = q ? A
"rank" ⎕S̲IGNAL ref c̲at " indexes " c̲at (f̲ormat q) c̲at " axes, but " c̲at name c̲at " has rank " c̲at f̲ormat t̲ally s̲hape A
}
g19:grid ← 4
g20:g̲rid ← { k → g19:grid r̲eshape (o̲ffsets k s̲elect g19:grid) 'l̲eft t̲able ('× r̲/ k d̲rop g19:grid) r̲eshape 0 }
g19:grid r̲eshape ((({ @ →
g21:grid ← 4 c̲at ({ v → (0 ≤ v) ? v◆ "bad-equation" ⎕S̲IGNAL "sum's range runs low..high: 0..3" } (1 + 3 − 0))
g22:g̲rid ← { k → g21:grid r̲eshape (o̲ffsets k s̲elect g21:grid) 'l̲eft t̲able ('× r̲/ k d̲rop g21:grid) r̲eshape 0 }
'+ r̲/₂ g21:grid r̲eshape ((
((g16:r̲ank (W, "W", 2, "W[i,j]")) g18:a̲t ((
((W, "W", 2, "j") g17:c̲heck (0 + g22:g̲rid 2)) + (2 s̲elect s̲hape W) ×
((W, "W", 1, "i") g17:c̲heck (0 + g22:g̲rid 1))))) ×
((g16:r̲ank (x, "x", 1, "x[j]")) g18:a̲t (
((x, "x", 1, "j") g17:c̲heck (0 + g22:g̲rid 2))))))
} @) + (s ×
((g16:r̲ank (u, "u", 1, "u[i]")) g18:a̲t (
((u, "u", 1, "i") g17:c̲heck (0 + g20:g̲rid 1)))))))
} @))