1 /* Pure Maxima implementation of PSLQ algorithm,
2 * from: https://www.davidhbailey.com/dhbpapers/pslq-cse.pdf
3 * Section 2, "The PSLQ Algorithm".
7 Let x be the n-long input real vector, and let nint denote the nearest integer function.
9 Then perform the following operations:
13 1. Set the n × n matrices A and B to the identity.
15 2. Compute the n-long vector s as s[k] := sqrt(sum(x[j]^2, j, k, n)),
16 and set y to the x vector, normalized by s[1].
18 3. Compute the initial n × (n − 1) matrix H as
20 H[j,j] := s[j + 1]/s[j], and
21 H[i,j] := −y[i] y[j] /(s[j] s[j+1]) if i > j.
25 for j := i − 1 to 1 step −1:
26 set t := nint(H[i,j] / H[j,j]); and y[j] := y[j] + t y[i];
28 set H[i,k] := H[i,k] − t H[j,k];
31 set A[i,k] := A[i,k] − t A[j,k] and B[k,j] := B[k,j] + t B[k,i];
36 Iterate until an entry of y is within a reasonable tolerance of zero,
37 or precision has been exhausted:
39 1. Select m such that γ^i |H[i,i]| is maximal when i = m.
41 2. Exchange the entries of y indexed m and m + 1,
42 the corresponding rows of A and H,
43 and the corresponding columns of B.
45 3. Remove the corner on H diagonal:
47 then set t0 := sqrt(H[m,m]^2 + H[m,m + 1]^2),
49 and t2 := H[m,m + 1]/t0;
53 H[i,m] := t1 t3 + t2 t4
54 and H[i,m + 1] := −t2 t3 + t1 t4;
60 for j := min(i − 1, m + 1) to 1 step −1:
61 set t := nint(H[i,j] /H[j,j])
62 and y[j] := y[j] + t y[i];
64 set H[i,k] := H[i,k] − t H[j, k];
67 set A[i,k] := A[i,k] − t A[j,k] and B[k,j] := B[k,j] + t B[k,i];
72 5. Norm bound: Compute M := 1/ max[j] |H[j,j]|.
73 Then there can exist no relation vector whose Euclidean norm is less than M.
75 Upon completion, the desired relation is found in the column of B corresponding to the
80 * NOTE 1: This implementation only implements the steps outlined in the paper;
81 * there is no outer loop to control looping until a criterion is met.
82 * The initialization step is pslq_init (no arguments, x is a global variable)
83 * and pslq_iterate (no arguments, intermediate results are global variables).
85 * NOTE 2: I have translated the stated algorithm carefully, but it should
86 * probably be reviewed for accuracy.
92 (kill (A, B, s, n, y, H),
95 /* 1. Set the n × n matrices A and B to the identity. */
99 /* 2. Compute the n-long vector s as s[k] := sqrt(sum(x[j]^2, j, k, n)), */
100 s: makelist (sqrt (sum (x[j]^2, j, k, n)), k, 1, n),
102 /* and set y to the x vector, normalized by s[1]. */
105 /* 3. Compute the initial n × (n − 1) matrix H as
106 * H[i,j] = 0 if i < j,
107 * H[j,j] := s[j + 1]/s[j], and
108 * H[i,j] := −y[i] y[j] /(s[j] s[j+1]) if i > j.
111 H: zeromatrix (n, n - 1),
112 for j thru n - 1 do H[j, j]: s[j + 1]/s[j],
115 do H[i, j]: - y[i] * y[j] / (s[j] * s[j + 1]),
119 * for j := i − 1 to 1 step −1:
120 * set t := nint(H[i,j] / H[j,j]); and y[j] := y[j] + t y[i];
122 * set H[i,k] := H[i,k] − t H[j,k];
125 * set A[i,k] := A[i,k] − t A[j,k] and B[k,j] := B[k,j] + t B[k,i];
131 (print ("pslq_init: just before step 4 (reduce H)."),
132 display (A, B, s, y, H)),
135 do for j: i - 1 thru 1 step -1
136 do block ([t: nint (H[i, j] / H[j, j])],
137 y[j]: y[j] + t * y[i],
139 do H[i, k]: H[i, k] - t * H[j, k],
141 do (A[i, k]: A[i, k] - t * A[j, k],
142 B[k, j]: B[k, j] + t * B[k, i])));
144 nint (x) := round (x);
146 /* Iterate until an entry of y is within a reasonable tolerance of zero,
147 * or precision has been exhausted:
153 (/* 1. Select m such that γ^i |H[i,i]| is maximal when i = m. */
155 max_foo: gamma * abs (H[1, 1]),
158 do block ([foo: gamma^i * abs (H[i, i])],
160 then (max_foo: foo, max_foo_i: i)),
163 /* 2. Exchange the entries of y indexed m and m + 1,
164 * the corresponding rows of A and H,
165 * and the corresponding columns of B.
168 exchange_elements (y, m, m + 1),
169 exchange_rows (A, m, m + 1),
170 exchange_rows (H, m, m + 1),
171 exchange_columns (B, m, m + 1),
173 /* 3. Remove the corner on H diagonal:
175 * then set t0 := sqrt(H[m,m]^2 + H[m,m + 1]^2),
177 * and t2 := H[m,m + 1]/t0;
181 * H[i,m] := t1 t3 + t2 t4
182 * and H[i,m + 1] := −t2 t3 + t1 t4;
188 then block ([t0, t1, t2, t3, t4],
189 t0: sqrt (H[m, m]^2 + H[m, m + 1]^2),
191 t2: H[m, m + 1] / t0,
195 H[i, m]: t1 * t3 + t2 * t4,
196 H[i, m + 1]: -t2 * t3 + t1 * t4)),
199 * For i := m + 1 to n:
200 * for j := min(i − 1, m + 1) to 1 step −1:
201 * set t := nint(H[i,j] /H[j,j])
202 * and y[j] := y[j] + t y[i];
204 * set H[i,k] := H[i,k] − t H[j, k];
207 * set A[i,k] := A[i,k] − t A[j,k] and B[k,j] := B[k,j] + t B[k,i];
214 do for j: min(i - 1, m + 1) thru 1 step -1
215 do block ([t: nint (H[i, j] / H[j, j])],
216 y[j]: y[j] + t * y[i],
218 do H[i, k]: H[i, k] - t * H[j, k],
220 do (A[i, k]: A[i, k] - t * A[j, k],
221 B[k, j]: B[k, j] + t * B[k, i])),
223 /* 5. Norm bound: Compute M := 1/ max[j] |H[j,j]|.
224 * Then there can exist no relation vector whose Euclidean norm is less than M.
227 M: 1 / lmax (makelist (abs (H[j, j]), j, 1, n - 1)));
229 /* Upon completion, the desired relation is found in the column of B corresponding to the
233 exchange_elements (l, i, j) := ([l[j], l[i]]: [l[i], l[j]], l);
234 exchange_rows (M, i, j) := ([M[j], M[i]]: [M[i], M[j]], M);
235 exchange_columns (M, i, j) := transpose (exchange_rows (transpose (M), i, j));