sourcelibs/Polynomials/src/Polynomials.xtl
1⍝# Polynomials: polynomials -- evaluation, sums, products, derivatives,
2⍝# integrals, real roots, text.
3⍝# Import it with an alias of your choice: "py:" u_se< "Polynomials".
4⍝# Put libs/Polynomials/src on XETAL_PATH ("just path"); the reference is libs/Polynomials/docs.
5⍝# Names with l: are exported; those under h: are private to this file.
6⍝#
7⍝# A polynomial is its coefficients, highest power first, as APL's
8⍝# decode reads digits: 3 -2 1 is 3x^2 - 2x + 1. Results are Floats.
9
10ᵗ⁼u̲se< "Strings"
11ᶠ⁼u̲se< "Format"
12
13⍝## Evaluation
14
15⍝# p a_t x: p's value at each x: the coefficients decoded in radix x
16⍝# (APL's decode is Horner's rule, on any numbers).
17ˡa̲t ← { p x → c ← f̲loat p◆ '{ v → v d̲ecode c } e̲ach f̲loat x }
18
19⍝## Arithmetic
20
21⍝# p without its leading zeros (at least one coefficient kept).
22ʰt̲rim ← { p → n ← t̲ally w̲here '∧ s̲\ p = 0◆ (n m̲in (t̲ally p) − 1) d̲rop p }
23
24⍝# a p_lus b: the sum.
25ˡp̲lus ← { a b →
26 n ← (t̲ally a) m̲ax t̲ally b
27 ʰt̲rim ((n̲eg n) t̲ake f̲loat a) + (n̲eg n) t̲ake f̲loat b
28}
29
30⍝# a t_imes b: the product: every product of a coefficient of a with
31⍝# one of b, summed by the power it belongs to.
32ˡt̲imes ← { a b →
33 m ← (f̲loat a) '× t̲able f̲loat b
34 k ← r̲avel (o̲ffsets t̲ally a) '+ t̲able o̲ffsets t̲ally b
35 v ← r̲avel m
36 ʰt̲rim '{ i → '+ r̲/ (k = i) r̲eplicate v } e̲ach o̲ffsets (t̲ally a) + (t̲ally b) − 1
37}
38
39⍝# d_erivative p: the derivative (0 for a constant).
40ˡd̲erivative ← { p →
41 1 = t̲ally p ? 1 r̲eshape 0.0
42 -1 d̲rop (f̲loat p) × f̲loat r̲ev o̲ffsets t̲ally p
43}
44
45⍝# i_ntegral p: the integral that is 0 at 0.
46ˡi̲ntegral ← { p → ((f̲loat p) ÷ f̲loat 1 + r̲ev o̲ffsets t̲ally p) c̲at 0.0 }
47
48⍝## Roots
49
50⍝# One Newton step for every x at once (a flat spot is nudged, not
51⍝# divided by).
52ʰs̲tep ← { p x →
53 d ← (ˡd̲erivative p) ˡa̲t x
54 x − (p ˡa̲t x) ÷ d + 0.000000000001 × f̲loat d = 0.0
55}
56
57⍝# r_oots p: the real roots, found by Newton's method from 64 starting
58⍝# points spread over the interval holding them all (Cauchy's bound),
59⍝# kept where the value is 0 to within 1e-9, rounded to 9 decimals.
60ˡr̲oots ← { p →
61 q ← ʰt̲rim f̲loat p
62 1 = t̲ally q ? 0 r̲eshape 0.0
63 b ← 1.0 + 'm̲ax r̲/ a̲bs (1 d̲rop q) ÷ f̲irst q
64 x ← 60 '{ y → q ʰs̲tep y } p̲ower b × ((f̲loat o̲ffsets 64) ÷ 31.5) − 1.0
65 x ← (0.000000001 > a̲bs q ˡa̲t x) r̲eplicate x
66 s̲ort u̲nique (f̲loat f̲loor 0.5 + x × 1000000000.0) ÷ 1000000000.0
67}
68
69⍝## Text
70
71⍝# A coefficient's size as text: whole numbers without a point.
72ʰs̲ize ← { c → a ← a̲bs c◆ a = f̲loat f̲loor a ? f̲ormat f̲loor a◆ f̲ormat a }
73
74⍝# x to the power k, as text.
75ʰp̲ow ← { k → k = 0 ? ""◆ k = 1 ? "x"◆ "x^" c̲at f̲ormat k }
76
77⍝# One term, without its sign: the size (left out when it is 1 and a
78⍝# power of x follows) and the power.
79ʰt̲erm ← { c k → (k > 0) ∧ 1.0 = a̲bs c ? ʰp̲ow k◆ (ʰs̲ize c) c̲at ʰp̲ow k }
80
81⍝# The sign between terms.
82ʰs̲ep ← { c → c < 0.0 ? " - "◆ " + " }
83
84⍝# t_ext p: the polynomial as text, 3x^2 - 2x + 1.
85ˡt̲ext ← { p →
86 c0 ← f̲loat ʰt̲rim p
87 keep ← (c0 ≠ 0.0) ∨ 1 = t̲ally c0
88 c ← keep r̲eplicate c0
89 k ← keep r̲eplicate r̲ev o̲ffsets t̲ally c0
90 first ← (((f̲irst c) < 0.0) r̲eplicate "-") c̲at (f̲irst c) ʰt̲erm f̲irst k
91 rest ← '{ i → (ʰs̲ep f̲irst i s̲elect c) c̲at (f̲irst i s̲elect c) ʰt̲erm f̲irst i s̲elect k } m̲ap 1 d̲rop r̲ange t̲ally c
92 first c̲at "" ᵗj̲oin rest
93}