import apple
import matplotlib.pyplot as plt
xs=apple.jit('[cos.(2*𝜋*x)*√(_2*_.y)]`(𝔯 0 1::Vec 1000 float) (𝔯 0 1)')()
plt.hist(xs);plt.show()
Apple is an experimental compiler with a typed frontend inhabited by two demons.
The REPL and typechecker are available on the release page.
In the REPL, type \l.
vanessa@MacBookAir apple % arepl
> \l
Λ scan √ sqrt
⋉ max ⋊ min
⍳ integer range ⌊, ⌈ floor, ceiling
e: exp ⨳ {m,n} convolve
\~ successive application \`n infix
_. log ' map
` zip `{i,j∘[k,l]} rank
𝒻 range (real) 𝜋 pi
⋮
Use :ty for more:
> :ty (⊲)
a → Vec i a → Vec (i + 1) a
:help inside the REPL:
> :help
:help, :h Show this help
:ty <expression> Display the type of an expression
:ann <expression> Annotate with types
:bench, :b <expression> Benchmark an expression
:list List all names that are in scope
⋮
There is a vim plugin and a VSCode extension.
The file extension is .🍎 or .🍏.
To generate an integer range use ..
(..)
: int → int → Vec #n int
.. is a binary operator taking a start value and end
value as arguments, viz.
> 1..9
Vec 9 [1, 2, 3, 4, 5, 6, 7, 8, 9]
⍳ generates an integer range beginning with 0.
> ⍳
⍳
: int(n) → Vec (n + 1) int
> ⍳9
Vec 10 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
For a range of real numbers, use frange or
𝒻.
> :ty frange
float → float → int → Vec #n float
frange takes a start value, an end value, and the number
of steps.
> frange 0 9 10
[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
' maps over an array.
> (*2)'⍳ 0 9
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
Functions can be curried.
Pick the greater value among two vectors:
> (⋉)`⟨0,_1,3.0⟩ ⟨_3,1,3⟩
Vec 3 [0.0, 1.0, 3.0]
/ folds over an array.
> (+)/⍳ 1 100
5050
> (+)Λ 1..3
Vec 3 [1, 3, 6]
Array literals are delineated by ⟨…⟩.
> ⟨_1,0::int⟩
[-1, 0]
> ⟨⟨0,1⟩,⟨_1,0::int⟩⟩
[ [0, 1]
, [-1, 0] ]
𝔸21
will be interpreted as
⟨2,1⟩
This only works for single-digit numbers, but cosmically justified numbers tend to be small.
⍋ sorts a numeric array.
> ⍋ (rand. _20 20 :: Vec 13 int)
Vec 13 [-17, -13, -10, -9, -7, -7, -7, -5, 2, 3, 4, 12, 17]
ᶥ (postfix) returns a vector of indices with the same
length as the leading axis of its argument.
> :ty [xᶥ]
Vec i a → Vec i int
> frange _10 0 11
Vec 11 [-10.0, -9.0, -8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0]
> (frange _10 0 11)ᶥ
Vec 11 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
~ reverses an array.
> ~(⍳9)
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
Reverse applied to a higher-dimensional array reverses elements (sub-arrays) along the first dimension.
> ⟨⟨0,1⟩,⟨1,0::int⟩,⟨2,4⟩⟩
[ [0, 1]
, [1, 0]
, [2, 4] ]
> ~⟨⟨0,1⟩,⟨1,0::int⟩,⟨2,4⟩⟩
[ [2, 4]
, [1, 0]
, [0, 1] ]
> ~'⟨⟨0,1⟩,⟨1,0::int⟩,⟨2,4⟩⟩
[ [1, 0]
, [0, 1]
, [4, 2] ]
The outer product ⊗ creates a table by applying some
function.
> :ty \f.\x.\y. x f⊗ y
(a → b → c) → Arr sh0 a → Arr sh1 b → Arr (sh0 ⧺ sh1) c
> (frange 0 9 10) (*)⊗ (frange 0 9 10)
[ [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
, [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
, [0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0]
, [0.0, 3.0, 6.0, 9.0, 12.0, 15.0, 18.0, 21.0, 24.0, 27.0]
, [0.0, 4.0, 8.0, 12.0, 16.0, 20.0, 24.0, 28.0, 32.0, 36.0]
, [0.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0]
, [0.0, 6.0, 12.0, 18.0, 24.0, 30.0, 36.0, 42.0, 48.0, 54.0]
, [0.0, 7.0, 14.0, 21.0, 28.0, 35.0, 42.0, 49.0, 56.0, 63.0]
, [0.0, 8.0, 16.0, 24.0, 32.0, 40.0, 48.0, 56.0, 64.0, 72.0]
, [0.0, 9.0, 18.0, 27.0, 36.0, 45.0, 54.0, 63.0, 72.0, 81.0] ]
> (frange 0 4 5) [(x,y)]⊗ (frange 0 4 5)
[ [(0.0*0.0), (0.0*1.0), (0.0*2.0), (0.0*3.0), (0.0*4.0)]
, [(1.0*0.0), (1.0*1.0), (1.0*2.0), (1.0*3.0), (1.0*4.0)]
, [(2.0*0.0), (2.0*1.0), (2.0*2.0), (2.0*3.0), (2.0*4.0)]
, [(3.0*0.0), (3.0*1.0), (3.0*2.0), (3.0*3.0), (3.0*4.0)]
, [(4.0*0.0), (4.0*1.0), (4.0*2.0), (4.0*3.0), (4.0*4.0)] ]
♭ flattens an array to a vector, ♯ adds a
dimension.
> :ty λA. ♭ (A::Arr (28×28×1) a)
Arr (28 × 28 × 1) a → Vec 784 a
> ♯ (⍳9)
Arr (1×10) [ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] ]
> :ty (\~)
(a → a → b) → Arr (i + 1 `Cons` sh) a → Arr (i `Cons` sh) b
[(-)\~ x] gives successive differences.
> (-)\~ ((^2)'(frange 0 9 10))
[1.0, 3.0, 5.0, 7.0, 9.0, 11.0, 13.0, 15.0, 17.0]
> (⊖)
(⊖) : int → Vec i a → Vec i a
> 2 ⊖ ⍳9
[2, 3, 4, 5, 6, 7, 8, 9, 0, 1]
> _2 ⊖ ⍳9
[8, 9, 0, 1, 2, 3, 4, 5, 6, 7]
> 2 ⊖ ⟨⟨1,2⟩,⟨3,4⟩,⟨5,6.0⟩⟩
Arr (3×2) [ [5.0, 6.0]
, [1.0, 2.0]
, [3.0, 4.0] ]
cyc. or ⊙ (infix) concatenates an array
with itself a specified number of times.
> cyc. ⟨0::int,1⟩ 4
Vec 8 [0, 1, 0, 1, 0, 1, 0, 1]
> ⟨0::int,1⟩⊙4
Vec 8 [0, 1, 0, 1, 0, 1, 0, 1]
> ⟨1.0,0⟩〃3
Arr (3×2) [ [1.0, 0.0]
, [1.0, 0.0]
, [1.0, 0.0] ]
⍉ or |:
> ⍉ ⟨⟨1.0,3⟩,⟨4,4⟩,⟨2,_2⟩⟩
[ [1.0, 4.0, 2.0]
, [3.0, 4.0, -2.0] ]
> ⟨⟨1.0,3⟩,⟨4,4⟩,⟨2,_2⟩⟩
[ [1.0, 3.0]
, [4.0, 4.0]
, [2.0, -2.0] ]
> gen. (1::int) (*2) 10
Vec 10 [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
Moving average:
> [(+)/x%ℝ(:x)]\` 7 (frange 0 9 10)
[3.0, 4.0, 5.0, 6.0]
> [x]\`4 (frange 0 5 6)
[ [0.0, 1.0, 2.0, 3.0]
, [1.0, 2.0, 3.0, 4.0]
, [2.0, 3.0, 4.0, 5.0] ]
> {i←2::int;i*i}
4
Bind, preventing inlining:
> {i⟜2::int;i*i}
4
One can see that 2 is stored in a register by inspecting
the generated assembly:
> :asm {i←2::int;i*i}
mov x0, #0x4
ret
> :asm {i⟜2::int;i*i}
mov x0, #0x2
mul x0, x0, x0
ret
> {sum ⇐ [(+)/x]; sum (⍳ 9)+⌊(sum(frange 0 9 10))}
90
> {sum ← [(+)/x]; sum (⍳ 9)+⌊(sum(frange 0 9 10))}
1:42: could not unify 'float' with 'int' in expression '𝒻 0 9 10'
𝓕 is like gen. but with access to all
previously computed values.
> :ty 𝓕
Vec m a → (Vec k a → a) → int(n) → Vec (m + n) a
Fibonacci sequence:
> 𝓕 ⟨1::int,1⟩ [}.x+}.(}:x)] 10
Vec 11 [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
> :ty ug.
(b → (b * a)) → b → int(n) → Vec n a
Rank `{i,j∘[k,l]} or `{i,j[k,l]} lifts a
function to operate on i, j-cells, optionally specifying axes k,l.
Iteration is bottom-up; by contrast map ' cuts across the
leading dimension.
To make a scalar function apply to arrays, re-rank
> :ty ((*)`{0,0})
(IsNum c) :=> Arr sh c → Arr sh c → Arr sh c
Sigmoid on an arbitrary-dimension array:
([1%(1+e:(_x))]`{0}) > ⟨⟨0,1,2⟩,⟨3,4,5::int⟩⟩
Arr (2×3) [ [0, 1, 2]
, [3, 4, 5] ]
> ((+)/)`{1} ⟨⟨0,1,2⟩,⟨3,4,5::int⟩⟩
Vec 3 [3, 5, 7]
> ((+)/)`{1∘[2]} ⟨⟨0,1,2⟩,⟨3,4,5::int⟩⟩
Vec 2 [3, 12]
This may be confusing; Apple’s rank feature was poorly designed.
Take 0-cells (scalars) from the first array and 1-cells from the second.
> (⊲)`{0,1[2]} ⟨0::int,1⟩ ⟨⟨2,3⟩,⟨4,5⟩⟩
Arr (2×3) [ [0, 2, 3]
, [1, 4, 5] ]
> ⍉ ((2 ⊖)`{1} ⟨⟨1,2⟩,⟨3,4⟩,⟨5,6.0⟩⟩)
Arr (3×2) [ [5.0, 6.0]
, [1.0, 2.0]
, [3.0, 4.0] ]
> :ty [♭`{3∘[2,3,4]} (x :: Arr (60000 × 28 × 28 × 1) float)]
Arr (60000 × 28 × 28 × 1) float → Arr (60000 × 784) float
> :store a ⟨⟨⟨0::int,1,2,3⟩,⟨4,5,6,7⟩,⟨8,9,10,11⟩⟩,⟨⟨12,13,14,15⟩,⟨16,17,18,19⟩,⟨20,21,22,23⟩⟩⟩
> ((+)/)`{1} a
Arr (3×4) [ [12, 14, 16, 18]
, [20, 22, 24, 26]
, [28, 30, 32, 34] ]
> ((+)/)`{1∘[2]} a
Arr (2×4) [ [12, 15, 18, 21]
, [48, 51, 54, 57] ]
> ((+)/)`{1∘[3]} a
Arr (2×3) [ [6, 22, 38]
, [54, 70, 86] ]
> [(+)/* 0 x]`{2} a
Vec 4 [60, 66, 72, 78]
> [(+)/* 0 x]`{2∘[1,3]} a
Vec 3 [60, 92, 124]
> [(+)/* 0 x]`{2∘[2,3]} a
Vec 2 [66, 210]
For comparison:
> [(+)/* 0 (x::M int)]'a
Vec 2 [66, 210]
> (+)/* 0 a
276
x⋅y is shorthand for (+)/(*)`x y.
𝔯 or rand.
> 𝔯 0 1 :: float
0.582699021207219
> 𝔯 0 1 :: Arr (3 × 3) float
Arr (3×3) [ [0.9827522631010304, 0.30678513061418045, 0.6008551364891055]
, [0.608715653358658, 0.2124387982011875, 0.8858951305876062]
, [0.30465710174579286, 0.15185986406856955, 0.33766190287353126] ]
Use ->n to access the nth element of a
tuple, viz.
> (1.0,#t,4::int)->1
1.0
> (1.0,#t,4::int)->2
#t
> (1.0,#t,4::int)->3
4
Convolve (⨳ {m,n}) is like infix
for higher-rank windows. One can also write (# {m,n}).
> [(⋉)/x] ⨳ {3} ⟨_1,0,4,_2,3,3,1,1,0,_5.0⟩
Vec 8 [4.0, 4.0, 4.0, 3.0, 3.0, 3.0, 1.0, 1.0]
> [(⋉)/x] \`3 ⟨_1,0,4,_2,3,3,1,1,0,_5.0⟩
Vec 8 [4.0, 4.0, 4.0, 3.0, 3.0, 3.0, 1.0, 1.0]
> ([(+)/* 0 (x::Arr (2×3) float)%ℝ(:x)] # {2,3}) ⟨⟨1.0,2,0,0⟩,⟨_1,_2,3,4⟩,⟨5,6,3,1⟩,⟨3,1,1,3⟩⟩
Arr (3×2) [ [0.5, 1.1666666666666665]
, [2.333333333333333, 2.5]
, [3.1666666666666665, 2.5] ]
(⨳ {m∘k,n∘l}) specifies the skip between windows/blocks,
viz.
> ([(⋉)/* _1e100 (x::M float)] ⨳ {2∘2,2∘2}) ⟨⟨20.0,200,_5,23⟩,⟨_13,134,119,100⟩,⟨120,32,49,25⟩,⟨_120,12,9,23⟩⟩
Arr (2×2) [ [200.0, 119.0]
, [120.0, 49.0] ]
> ([(⋉)/* _1e100 (x::M float)] ⨳ {2,2∘2}) ⟨⟨20.0,200,_5,23⟩,⟨_13,134,119,100⟩,⟨120,32,49,25⟩,⟨_120,12,9,23⟩⟩
Arr (3×2) [ [200.0, 119.0]
, [134.0, 119.0]
, [120.0, 49.0] ]
> :ty 𝐒
(a → b → c) → (a → b) → a → c
> :ty 𝐊
b → a → b
Haskell’s on,
Curry’s Φ
combinator):
> :ty (⑂)
(b → b → c) → (a → b) → a → a → c
One can define the logarithm in any base from the natural logarithm
_., viz.
> ([y%x]⑂_.) 2 8
3.0
> :ty refl.
(float → float) → float → float
Computes odd functions from the positive half. Arcsine:
refl. (λz. {
as ⟜ ⟨1.5707288,_0.2121144,0.0742610,_0.0187293⟩;
Ho ← gen. 1 (z*) 4;
𝜋%2-√(1-z)*Ho⋅as
}) > :yank chisqcdf math/chisqcdf.🍎
> chisqcdf 10 28
0.9982004955179669
math/chisqcdf.🍎 is a file that contains an expression
of type float → float→ float.
> :bench frange 0 999 1000
benchmarking...
time 1.423 μs (1.417 μs .. 1.427 μs)
1.000 R² (1.000 R² .. 1.000 R²)
mean 1.426 μs (1.422 μs .. 1.429 μs)
std dev 11.94 ns (9.819 ns .. 14.22 ns)
Apple can generate shape-correct test cases for property testing. For instance,
> :qc \x. [(+)/(*)`x y] x x >= 0.0
Passed, 100.
tests that the dot product of a vector with itself is nonnegative.
Instead of
{x←y;z}One can write
⸎x←y;zUsing the typographical coronis.
One can specify matrix dimensions in a type signature with unicode subscript digits separated by a comma.
𝔯 0 1 :: M ₁₂,₁₂ floatis equivalent to
𝔯 0 1 :: Arr (12 × 12) floatIdentifiers may be latin or greek characters, or a single character
from the mathematical greek or mathematical latin unicode block,
optionally followed by some subscript alphanumeric characters.
∂ may appear at the beginning of multi-character
identifiers or on its own. The single-character lambda λ is
reserved. ∫, 𝛻, and ∇ are also
identifiers but may not be followed by a subscript.
Thus pxs, aₙ, sn₁,
𝐶, φs, ∂f, 𝜉, and
𝜌₀ are valid identifiers but 𝜉s,
𝜉∂, and f∂ are parsed as application of one
identifier to another.
Unicode vulgar fractions are considered float literals:
> ⅚
0.8333333333333334
One can use ⅟ for the reciprocal, viz.
> [⅟(1+e:(_x))]
λx. 1.0 % (1 + 2.718281828459045 ** _ x) : float → float
In the REPL, one can use ⏱ in place of
:bench, i.e.
> ⏱ [(+)/x%ℝ(:x)]\`7 (𝒻 0 999 1000)
𝟘 can be used in place of int, viz.
> 17*3::𝟘
51
> 𝔯 1 6::𝟘
5
> 𝔯 1 6::Vec 6 𝟘
Vec 6 [6, 2, 1, 5, 5, 3]
𝞈 is shorthand for float.
> 𝔯 0 1::𝞈
0.8404853694114252
𝟙 is shorthand for Vec n, n an
index variable. 𝟚 is a synonym for M.
The cross product of two vectors \((a_1,a_2,a_3)\), \((b_1,b_2,b_3) \in \mathbb{R}^3\) is the vector \(\in\mathbb{R}^3\)
\[(a_2b_3-a_3b2, a_3b1-a_1b3,a_1b_2-a_2b_1)\]
In Apple, we can write:
λa.λb. (-)`((*)`(1⊖a) (_1⊖b)) ((*)`(_1⊖a) (1⊖b))This uses zips and rotations (no indices are mentioned); it is a new perspective on the problem.
λxs.λys.
{
Σ ← [(+)/x];
n ⟜ ℝ(:xs);
xbar ⟜ Σ xs % n; ybar ⟜ Σ ys % n;
xy ⟜ Σ ((*)`xs ys);
x2 ⟜ Σ ((^2)'xs);
denom ⟜ x2-n*xbar^2;
a ← (ybar*x2-xbar*xy)%denom;
b ← (xy-n*xbar*ybar)%denom;
(a,b)
}Note the ⟜ to prevent expressions from being
inlined.
λp.λq. (+)/([x*_.(x%y)]`p q)λxs.
⸎ avg ← [{n ⟜ ℝ(:xs); ((+)/xs)%n}]
; e:(avg (_.'xs))λds. }:((*)Λₒ 1::int ds)(Column-major order)
λwh.λwo.λbh.λbo.
{ X ⟜ ⟨⟨0,0⟩,⟨0,1⟩,⟨1,0⟩,⟨1,1⟩⟩;
Y ← ⟨0,1,1,0⟩;
sigmoid ← [1%(1+e:(_x))];
sDdx ← [x*(1-x)];
sum ⇐ [(+)/x];
ho ⟜ sigmoid`{0} ([(+)`bh x]'(X%.wh));
prediction ⟜ (sigmoid ∴ (+bo))'(ho%:wo);
l1E ← (-)`Y prediction;
l1Δ ⟜ (*)`(sDdx'prediction) l1E;
he ← l1Δ (*)⊗ wo;
hΔ ⟜ (*)`{0,0} (sDdx`{0} ho) he;
wha ← (+)`{0,0} wh ((|:X)%.hΔ);
woa ← (+)`wo ((|:ho)%:l1Δ);
bha ← [(+)/ₒ x y]`{0,1} bh hΔ;
boa ← bo + sum l1Δ;
(wha,woa,bha,boa)
}This is equivalent to the Python:
import numpy as np
def sigmoid (x):
return 1/(1 + np.exp(-x))
def sigmoid_derivative(x):
return x * (1 - x)
inputs = np.array([[0,0],[0,1],[1,0],[1,1]])
expected_output = np.array([[0],[1],[1],[0]])
hidden_layer_activation = np.dot(inputs,hidden_weights)
hidden_layer_activation += hidden_bias
hidden_layer_output = sigmoid(hidden_layer_activation)
output_layer_activation = np.dot(hidden_layer_output,output_weights)
output_layer_activation += output_bias
predicted_output = sigmoid(output_layer_activation)
#Backpropagation
error = expected_output - predicted_output
d_predicted_output = error * sigmoid_derivative(predicted_output)
error_hidden_layer = d_predicted_output.dot(output_weights.T)
d_hidden_layer = error_hidden_layer * sigmoid_derivative(hidden_layer_output)
#Updating Weights and Biases
output_weights += hidden_layer_output.T.dot(d_predicted_output)
output_bias += np.sum(d_predicted_output,axis=0,keepdims=True)
hidden_weights += inputs.T.dot(d_hidden_layer)
hidden_bias += np.sum(d_hidden_layer,axis=0,keepdims=True)We will convert a permutation represented as a vector of integers into a Boolean matrix; then the transpose of this will be the inverse permutation (as a Boolean matrix).
To convert a permutation to its Boolean matrix representation:
[x (=)⊗ xᶥ] > [x (=)⊗ xᶥ] 𝔸021
Arr (3×3) [ [#t, #f, #f]
, [#f, #f, #t]
, [#f, #t, #f] ]
To convert back:
(([x]@.)') > ([x]@.)'([x (=)⊗ xᶥ] 𝔸021)
Vec 3 [0, 2, 1]
Putting it all together to get the inverse:
> ([x]@.)'(⍉([x (=)⊗ xᶥ] 𝔸120))
Vec 3 [2, 0, 1]
This uses @. (index-of), showing an array style that is
not appreciated in functional programming.
Hui, Iverson, and McDonnell give the lovely enumeration of permutations in reduced form:
λn.
{
fact ← [(*)/ₒ 1 (1..x)];
antibase ← λk.λbs. (->1)'({: ((λqr.λb. {s ⟜ qr->2; (s|b, s/.b)}) Λₒ (0,k) bs));
bs ⟜ 1..n;
(λk. ~(antibase k bs))'⍳ (fact n-1)
} > r 3
Arr (6×3) [ [0, 0, 0]
, [0, 1, 0]
, [1, 0, 0]
, [1, 1, 0]
, [2, 0, 0]
, [2, 1, 0] ]
antibase
can be used to convert seconds to hours-minutes-seconds:
> {antibase ← λk.λbs. (->1)'({: ((λqr.λb. {s ⟜ qr->2; (s|b, s/.b)}) Λₒ (0,k) bs)); antibase 86399 ⟨24,60,60⟩}
Vec 3 [23, 59, 59]
If a polygon has vertices at \(x_n\), \(y_n\), then its area is given by
\[A=\frac{1}{2}\Biggl|(x_1y_2+x_2y_3+\cdots+x_ny_1)-(y_1x_2+y_2x_3+\cdots+y_nx_1)\Biggr|\]
λxs.λys.
{ sum ⇐ [(+)/x]
; ½*abs.(sum((*)`xs (1⊖ys)) - sum((*)`(1⊖xs) ys))
}Note the array style: ⊖, ` (zip), and fold are enough to
eschew pointful definitions.
λp.λx. ~p⋅gen. 1 (*x) (𝓉p)To compute
\(\displaystyle \frac{p(x)}{x-a}\)
for \(p\) a polynomial:
λp.λa. {:((λs.λc. (a*s+c)) Λₒ 0 p)λa.λn. {log ← λb.λx. _.x%_.b;N ⟜ ⌊(log (ℝn) (ℝa))+1;~(ug. (λs. (s/.n, s|n)) a N)}Given a \(K \times N\) matrix of \(N\) obervations on \(K\) variables, we can compute the sample covariance matrix thusly:
λxs.
{
𝜇 ← [(+)/x%ℝ(:x)]; rs ← 𝜇'xs;
nd ⟜ [(-x)'y]`{0,1∘[2]} rs xs;
N ⟜ ℝ(:({.xs))-1;
nd [x⋅y%N]⊗ nd
}The array style gives a new take on the problem.
To take all but the last 6 elements:
[{.\`7 x]
To drop the first 6 elements:
[}.\`7 x]
Take the first 7 elements:
> {. ([x] \`7 ⍳ 9)
Vec 7 [0, 1, 2, 3, 4, 5, 6]
Take the last 7 elements:
> }. ([x] \`7 ⍳ 9)
Vec 7 [3, 4, 5, 6, 7, 8, 9]
> [x] # {2∘2} (frange 0 9 10)
Arr (5×2) [ [0.0, 1.0]
, [2.0, 3.0]
, [4.0, 5.0]
, [6.0, 7.0]
, [8.0, 9.0] ]
λA.λx. (x⋅)`{1∘[2]} (A::Arr (i × j) float)\p.\xs. (p⩪xs)⊂xs[{m⟜(⋉)/x::Vec n float; (=m)@.x}]λxs.
{ digitSum ← [?x>10,.x-9,.x]
; t ← (+)/ [digitSum (x*y)]`(~(}:xs)) (}: (𝔸21⊙8))
; 10-t|10=}.xs
}Note zipping with cyc. ⟨2,1::int⟩ 8 to get alternating
2, 1, … factors.
The Catalan numbers satisfy
\[C_n=\sum_{i=0}^{n-1}C_iC_{n-i-1}\]
where \(C_0=1,C_1=1,C_2=2\).
We can compute them in Apple with:
{ Σ ⇐ λl.λu.λf.(+)/ₒ 0 (f'l..u)
; 𝓕 ⟨1::int,1,2⟩ (λC. {n⟜ 𝓉C; Σ 0 (n-1) (λi. (C˙i*C˙(n-i-1)))})
}The use of “strong induction” provides a new take on the problem where Python uses memoization.
The number of unlabeled rooted trees with at most \(n\) nodes (this appears in chemistry (counting alkanes)).
{ sum ⇐ [(+)/ₒ 0 x]; Σ ⇐ λl.λu.λf. sum (f'l..u)
; divisors ← λn. (λk. (n|k=0))§⍳ n
; 𝓕 𝔸01 (λas. {n⟜ 𝓉as; Σ 1 (n-1) (λj.sum ((λd. d*as˙d)'(divisors j))*as˙(n-j))/.(n-1)})
}Cf. Reinhard Zumkeller’s Haskell solution by sharing/laziness.
From Kuhl and Giardnia, the coefficients are given by:
\[ a_n = \frac{T}{2n^2\pi^2}\sum_{p=1}^K \frac{\Delta x_p}{\Delta t_p}\left(\cos\frac{2n\pi t_p}{T} - \cos\frac{2n\pi t_{p-1}}{T}\right) \]
\[ b_n = \frac{T}{2n^2\pi^2}\sum_{p=1}^K \frac{\Delta x_p}{\Delta t_p}\left(\sin\frac{2n\pi t_p}{T} - \sin\frac{2n\pi t_{p-1}}{T}\right) \]
\[ c_n = \frac{T}{2n^2\pi^2}\sum_{p=1}^K \frac{\Delta y_p}{\Delta t_p}\left(\cos\frac{2n\pi t_p}{T} - \cos\frac{2n\pi t_{p-1}}{T}\right) \]
\[ d_n = \frac{T}{2n^2\pi^2}\sum_{p=1}^K \frac{\Delta y_p}{\Delta t_p}\left(\sin\frac{2n\pi t_p}{T} - \sin\frac{2n\pi t_{p-1}}{T}\right) \]
The offsets are given by:
\[ A_0 = \frac{1}{T} \sum_{p=1}^K \left[\frac{\Delta x_p}{2\Delta t_p} (t_p^2-t_{p-1}^2) + \xi_p (t_p-t_{p-1}^2)\right]\]
\[ C_0 = \frac{1}{T} \sum_{p=1}^K \left[\frac{\Delta y_p}{2\Delta t_p} (t_p^2-t_{p-1}^2) + \delta_p (t_p-t_{p-1}^2)\right]\]
where
\[ \xi_p = \sum_j^{p-1} \Delta x_j - \frac{\Delta x_p}{\Delta t_p} \sum_j^{p-1}\Delta t_j \]
\[ \delta_p = \sum_j^{p-1} \Delta y_j - \frac{\Delta y_p}{\Delta t_p} \sum_j^{p-1}\Delta t_j \]
\[ \xi_0,~\delta_0 = 0 \]
In Apple we can generate the first N coefficients
alongside the offsets with:
λxs.λys.λN.
{ tieSelf ← [({.x)⊳x]; Δ ← [(-)\~(tieSelf x)]
; dxs ⟜ Δ xs; dys ⟜ Δ ys
; dts ⟜ [√(x^2+y^2)]`dxs dys
; dxss ⟜ ((%)`dxs dts); dyss ⟜ ((%)`dys dts)
; pxs ← (+)Λ dxs; pys ← (+)Λ dys; pts ⟜ (+)Λₒ 0 dts; T ⟜}. pts
; coeffs ← λn.
{ n ⟜ ℝn; k ⟜ 2*n*𝜋%T
; c ⟜ T%(2*n^2*𝜋^2)
; cosDiffs ⟜ (-)\~(cos. ∴ (k*)'pts)
; sinDiffs ⟜ (-)\~(sin. ∴ (k*)'pts)
; aₙ ← c*dxss⋅cosDiffs
; cₙ ← c*dyss⋅cosDiffs
; bₙ ← c*dxss⋅sinDiffs
; dₙ ← c*dyss⋅sinDiffs
; (aₙ,bₙ,cₙ,dₙ)
}
; dtss ⟜ (-)\~((^2)'pts)
; ppts ⟜ {: pts
; 𝜉 ← (-)`pxs ((*)`((%)`dxs dts) ppts)
; 𝛿 ← (-)`pys ((*)`((%)`dys dts) ppts)
; A ← (½*((%)`dxs dts)⋅dtss + 𝜉⋅dts)%T
; C ← (½*((%)`dys dts)⋅dtss + 𝛿⋅dts)%T
; (coeffs'1..N,A,C)
}
Note the array style, e.g. (-)\~ to define successive
differences on an array rather than definining pointfully.
Let 𝜆₀, 𝜑₀ be the coördinates of the origin, 𝜑₁, 𝜑₂ standard
parallels, φs and lambdas the longitudes and
latitudes, respectively.
\𝜆₀.\𝜑₀.\𝜑₁.\𝜑₂.\φs.\lambdas.
{
𝑛 ⟜ (sin. 𝜑₁+sin.𝜑₂)%2;
𝐶 ⟜ (cos. 𝜑₁)^2+2*𝑛*sin. 𝜑₁;
𝜌₀ ⟜ √(𝐶-2*𝑛*sin. 𝜑₀)%𝑛;
albers ← \𝜑.\𝜆.
{
𝜃 ⟜ 𝑛*(𝜆-𝜆₀);
𝜌 ⟜ √(𝐶-2*𝑛*sin. 𝜑)%𝑛;
(𝜌*sin. 𝜃, 𝜌₀-𝜌*cos. 𝜃)
};
albers`φs lambdas
}λn.¬((∨)/ₒ #f ([(n|x)=0]'2..(⌊(√(ℝn)))))Compute the radical of an integer \(n\), \(\displaystyle \prod_{p|n} p\)
λn.
{ ni ⟜ ⌊(√(ℝn))
; isPrime ← λn.¬((∨)/ₒ #f ([n|x=0]'2..(⌊(√(ℝn)))))
; pf ⇐ (isPrime #.)
; pps ⟜ (λk. (n|k=0)) #. 2..ni
; ?ni^2=n
,.((*)/ₒ 1 (pf (pps⧺(n/.)'}:?pps)))
,.((*)/ₒ 1 (pf (n ⊲ pps⧺(n/.)'pps)))
}This shows the awkwardness of an array style.
To generate normally distributed random values, we can use
\[ X = \sqrt{-2 \log B_1} \cos (2\pi B_2) \]
where \(B_1\), \(B_2\) are uniformly distributed \(\in [0,1)\).
Debugging randomness is fraught, so we turn to Python’s visualization libraries.
import apple
import matplotlib.pyplot as plt
xs=apple.jit('[cos.(2*𝜋*x)*√(_2*_.y)]`(𝔯 0 1::Vec 1000 float) (𝔯 0 1)')()
plt.hist(xs);plt.show()