Commit | Line | Data |
---|---|---|
7f918cf1 CE |
1 | (* Written by Henry Cejtin (henry@sourcelight.com). *) |
2 | signature MATRIX = | |
3 | sig | |
4 | type 'entry matrix | |
5 | val make: int * int * (int * int -> 'entry) -> 'entry matrix | |
6 | val height: 'entry matrix -> int | |
7 | val width: 'entry matrix -> int | |
8 | val fetch: 'entry matrix * int * int -> 'entry | |
9 | val fetchRow: 'entry matrix * int -> int -> 'entry | |
10 | val fetchCol: 'entry matrix * int -> int -> 'entry | |
11 | val store: 'entry matrix * int * int * 'entry -> unit | |
12 | val storeRow: 'entry matrix * int -> int * 'entry -> unit | |
13 | val storeCol: 'entry matrix * int -> int * 'entry -> unit | |
14 | val rowSwap: 'entry matrix * int * int -> unit | |
15 | val colSwap: 'entry matrix * int * int -> unit | |
16 | val rowOp: 'entry matrix * int * int * ('entry * 'entry -> 'entry) -> unit | |
17 | val colOp: 'entry matrix * int * int * ('entry * 'entry -> 'entry) -> unit | |
18 | val copy: 'entry matrix -> 'entry matrix | |
19 | val map: 'entry1 matrix * ('entry1 -> 'entry2) -> 'entry2 matrix | |
20 | val toString: 'entry matrix * ('entry -> string) -> string | |
21 | end | |
22 | ||
23 | structure Matrix:> MATRIX = | |
24 | struct | |
25 | type 'entry matrix = int * int * 'entry array | |
26 | ||
27 | exception sizeError | |
28 | ||
29 | exception index | |
30 | ||
31 | exception foldError | |
32 | ||
33 | fun make (height: int, width: int, generator: int * int -> 'entry) | |
34 | : 'entry matrix = | |
35 | if height < 0 orelse width < 0 | |
36 | then raise sizeError | |
37 | else (height, | |
38 | width, | |
39 | Array.tabulate (height*width, | |
40 | fn z => generator (z div width, | |
41 | z mod width))) | |
42 | ||
43 | fun height (height, _, _) = height | |
44 | ||
45 | fun width (width, _, _) = width | |
46 | ||
47 | fun fetch ((height, width, mat), row, col) = | |
48 | if 0 <= row | |
49 | andalso row < height | |
50 | andalso 0 <= col | |
51 | andalso col < width | |
52 | then Array.sub (mat, col + width*row) | |
53 | else raise index | |
54 | ||
55 | fun fetchRow ((height, width, mat), row) = | |
56 | if 0 <= row andalso row < height | |
57 | then let val offset = width * row | |
58 | in fn col => | |
59 | if 0 <= col andalso col < width | |
60 | then Array.sub (mat, col + offset) | |
61 | else raise index | |
62 | end | |
63 | else raise index | |
64 | ||
65 | fun fetchCol ((height, width, mat), col) = | |
66 | if 0 <= col andalso col < width | |
67 | then fn row => | |
68 | if 0 <= row andalso row < height | |
69 | then Array.sub (mat, col + width*row) | |
70 | else raise index | |
71 | else raise index | |
72 | ||
73 | fun store ((height, width, mat), row, col, entry) = | |
74 | if 0 <= row | |
75 | andalso row < height | |
76 | andalso 0 <= col | |
77 | andalso col < width | |
78 | then Array.update (mat, col + width*row, entry) | |
79 | else raise index | |
80 | ||
81 | fun storeRow ((height, width, mat), row) = | |
82 | if 0 <= row andalso row < height | |
83 | then let val offset = width * row | |
84 | in fn (col, entry) => | |
85 | if 0 <= col andalso col < width | |
86 | then Array.update (mat, col + offset, entry) | |
87 | else raise index | |
88 | end | |
89 | else raise index | |
90 | ||
91 | fun storeCol ((height, width, mat), col) = | |
92 | if 0 <= col andalso col < width | |
93 | then fn (row, entry) => | |
94 | if 0 <= row andalso row < height | |
95 | then Array.update (mat, col + width*row, entry) | |
96 | else raise index | |
97 | else raise index | |
98 | ||
99 | fun swapLoop (from1: int -> 'entry, | |
100 | to1: int * 'entry -> unit, | |
101 | from2: int -> 'entry, | |
102 | to2: int * 'entry -> unit, | |
103 | limit: int): unit = | |
104 | let fun loop (i: int): unit = | |
105 | if i = limit | |
106 | then () | |
107 | else let val tmp = from1 i | |
108 | in to1 (i, from2 i); | |
109 | to2 (i, tmp); | |
110 | loop (i + 1) | |
111 | end | |
112 | in loop 0 | |
113 | end | |
114 | ||
115 | fun rowSwap (mat as (height, width, _), row1, row2): unit = | |
116 | if 0 <= row1 andalso row1 < height | |
117 | andalso 0 <= row2 andalso row2 < height | |
118 | then if row1 = row2 | |
119 | then () | |
120 | else swapLoop (fetchRow (mat, row1), | |
121 | storeRow (mat, row1), | |
122 | fetchRow (mat, row2), | |
123 | storeRow (mat, row2), | |
124 | width) | |
125 | else raise index | |
126 | ||
127 | fun colSwap (mat as (height, width, _), col1, col2): unit = | |
128 | if 0 <= col1 andalso col1 < width | |
129 | andalso 0 <= col2 andalso col2 < width | |
130 | then if col1 = col2 | |
131 | then () | |
132 | else swapLoop (fetchCol (mat, col1), | |
133 | storeCol (mat, col1), | |
134 | fetchCol (mat, col2), | |
135 | storeCol (mat, col2), | |
136 | height) | |
137 | else raise index | |
138 | ||
139 | fun opLoop (from1: int -> 'entry, | |
140 | from2: int -> 'entry, | |
141 | to2: int * 'entry -> unit, | |
142 | limit: int, | |
143 | f: 'entry * 'entry -> 'entry): unit = | |
144 | let fun loop (i: int): unit = | |
145 | if i = limit | |
146 | then () | |
147 | else ( | |
148 | to2 (i, | |
149 | f (from1 i, from2 i)); | |
150 | loop (i + 1)) | |
151 | in loop 0 | |
152 | end | |
153 | ||
154 | fun rowOp (mat as (height, width, _), | |
155 | row1, | |
156 | row2, | |
157 | f: 'entry * 'entry -> 'entry): unit = | |
158 | if 0 <= row1 andalso row1 < height | |
159 | andalso 0 <= row2 andalso row2 < height | |
160 | andalso row1 <> row2 | |
161 | then opLoop (fetchRow (mat, row1), | |
162 | fetchRow (mat, row2), | |
163 | storeRow (mat, row2), | |
164 | width, | |
165 | f) | |
166 | else raise index | |
167 | ||
168 | fun colOp (mat as (height, width, _), | |
169 | col1, | |
170 | col2, | |
171 | f: 'entry * 'entry -> 'entry): unit = | |
172 | if 0 <= col1 andalso col1 < width | |
173 | andalso 0 <= col2 andalso col2 < width | |
174 | andalso col1 <> col2 | |
175 | then opLoop (fetchCol (mat, col1), | |
176 | fetchCol (mat, col2), | |
177 | storeCol (mat, col2), | |
178 | height, | |
179 | f) | |
180 | else raise index | |
181 | ||
182 | fun copy ((height, width, mat)) = | |
183 | (height, | |
184 | width, | |
185 | Array.tabulate (Array.length mat, | |
186 | fn i => Array.sub (mat, i))) | |
187 | ||
188 | fun map ((height, width, mat: 'entry1 Array.array), | |
189 | f: 'entry1 -> 'entry2) | |
190 | : 'entry2 matrix = | |
191 | (height, | |
192 | width, | |
193 | Array.tabulate (Array.length mat, | |
194 | fn i => f (Array.sub (mat, i)))) | |
195 | ||
196 | (* Natural fold a range of integers in reverse. *) | |
197 | fun naturalFold (limit: int, | |
198 | state: 'state, | |
199 | folder: int * 'state -> 'state): 'state = | |
200 | let fun loop (i: int, state: 'state) = | |
201 | if i = 0 | |
202 | then state | |
203 | else loop (i - 1, folder (i - 1, state)) | |
204 | in if limit < 0 | |
205 | then raise foldError | |
206 | else loop (limit, state) | |
207 | end | |
208 | ||
209 | ||
210 | local val blank8 = Byte.charToByte #" " | |
211 | ||
212 | fun makeBlanks size = | |
213 | let val blanks = Word8Vector.tabulate (size, | |
214 | fn _ => blank8) | |
215 | in Byte.bytesToString blanks | |
216 | end | |
217 | ||
218 | in fun toString (mat: 'entry matrix, f: 'entry -> string): string = | |
219 | let val mat as (height, width, _) = map (mat, f) | |
220 | fun maxSize from (i, width) = Int.max (String.size (from i), | |
221 | width) | |
222 | fun colWidth col = naturalFold (height, | |
223 | 0, | |
224 | maxSize (fetchCol (mat, | |
225 | col))) | |
226 | val widths = Vector.tabulate (width, colWidth) | |
227 | fun doRow (row: int, ac: string list): string list = | |
228 | let val from = fetchRow (mat, row) | |
229 | fun loop (col: int, ac: string list) = | |
230 | let val next = from col | |
231 | val ac = next::ac | |
232 | val s = String.size next | |
233 | val pad = Vector.sub (widths, col) - s | |
234 | val ac = if pad <= 0 | |
235 | then ac | |
236 | else (makeBlanks pad)::ac | |
237 | in if col = 0 | |
238 | then ac | |
239 | else loop (col - 1, | |
240 | " "::ac) | |
241 | end | |
242 | val ac = "\n"::ac | |
243 | in if width = 0 | |
244 | then ac | |
245 | else loop (width - 1, ac) | |
246 | end | |
247 | val pieces = naturalFold (height, | |
248 | [], | |
249 | doRow) | |
250 | in String.concat pieces | |
251 | end | |
252 | end | |
253 | end | |
254 | ||
255 | val zero = IntInf.fromInt 0 | |
256 | ||
257 | fun smaller (a: IntInf.int, b: IntInf.int): bool = | |
258 | (not (a = zero)) | |
259 | andalso (b = zero orelse IntInf.< (IntInf.abs a , IntInf.abs b)) | |
260 | ||
261 | fun smithNormalForm (mat: IntInf.int Matrix.matrix): IntInf.int Matrix.matrix = | |
262 | let val height = Matrix.height mat | |
263 | val width = Matrix.width mat | |
264 | val mat = Matrix.copy mat | |
265 | val range = Int.min (width, height) | |
266 | fun dd pos = | |
267 | let val matCol = Matrix.fetchCol (mat, pos) | |
268 | val matRow = Matrix.fetchRow (mat, pos) | |
269 | val _ = print ("dd: pos = " ^ (Int.toString pos) ^ "\n") | |
270 | fun swapRowLoop (best, bestRow, bestCol, row) = | |
271 | if row >= height | |
272 | then (Matrix.rowSwap (mat, pos, bestRow); | |
273 | Matrix.colSwap (mat, pos, bestCol)) | |
274 | else let val matRow = Matrix.fetchRow (mat, row) | |
275 | fun swapColLoop (best, bestRow, bestCol, col) = | |
276 | if col >= width | |
277 | then swapRowLoop (best, bestRow, bestCol, row + 1) | |
278 | else let val next = matRow col | |
279 | in if smaller (next, best) | |
280 | then swapColLoop (next, row, col, col + 1) | |
281 | else swapColLoop (best, bestRow, bestCol, col + 1) | |
282 | end | |
283 | in swapColLoop (best, bestRow, bestCol, pos) | |
284 | end | |
285 | fun rowLoop row = | |
286 | if row < height | |
287 | then if (matCol row) = zero | |
288 | then rowLoop (row + 1) | |
289 | else (Matrix.rowOp (mat, | |
290 | pos, | |
291 | row, | |
292 | let val x = IntInf.~ (IntInf.quot(matCol row, matCol pos)) | |
293 | in fn (lhs, rhs) => IntInf.+ (IntInf.* (lhs, x), rhs) | |
294 | end); | |
295 | if (matCol row) = zero | |
296 | then rowLoop (row + 1) | |
297 | else hitPosAgain ()) | |
298 | else let fun colLoop col = | |
299 | if col < width | |
300 | then if (matRow col) = zero | |
301 | then colLoop (col + 1) | |
302 | else (Matrix.colOp (mat, | |
303 | pos, | |
304 | col, | |
305 | let val x = IntInf.~ (IntInf.quot (matRow col, matRow pos)) | |
306 | in fn (lhs, rhs) => IntInf.+ (IntInf.* (lhs, x), rhs) | |
307 | end); | |
308 | if (matRow col) = zero | |
309 | then colLoop (col + 1) | |
310 | else hitPosAgain ()) | |
311 | else () | |
312 | in colLoop (pos + 1) | |
313 | end | |
314 | and hitPosAgain () = (swapRowLoop (zero, pos, pos, pos); | |
315 | rowLoop (pos + 1)) | |
316 | in hitPosAgain () | |
317 | end | |
318 | fun loop pos = | |
319 | if pos = range | |
320 | then mat | |
321 | else (dd pos; | |
322 | loop (pos + 1)) | |
323 | in loop 0 | |
324 | end | |
325 | ||
326 | val table = [[ 8, ~3, 1, 3, 6, 9, ~2, 4, ~9, ~9, 2, 3, 8, ~1, 3, ~5, 4, ~3, ~5, ~6, 8, 1, 4, ~5, 7, ~4, ~4, ~7, 7, 1, 4, ~3, 8, 4, ~4, ~8, 5, ~9, 3, ~4, 1, 9, ~8, ~6, ~2, 8, ~9, ~5, ~3, ~3], | |
327 | [ 0, 8, ~6, ~2, ~3, 4, 5, ~2, 7, ~7, ~6, ~7, ~3, ~4, 9, 7, ~3, 3, 0, 3, 3, ~8, ~8, 2, 3, 8, 3, ~2, ~4, 3, ~6, ~6, ~2, 6, 5, ~1, ~3, 1, 8, ~8, 2, 1, ~7, ~7, ~7, ~3, ~6, 6, ~4, ~9], | |
328 | [ 0, ~5, 8, ~9, 2, 4, 2, 7, ~4, 9, ~3, 6, ~2, 3, ~3, 0, ~9, 5, 8, ~1, 2, ~8, 3, 4, ~6, 5, ~6, ~5, ~8, 0, ~5, 3, ~2, ~5, 8, 7, ~1, 1, ~1, 7, 6, 3, 6, 5, 6, 8, 7, 9, 7, ~3], | |
329 | [ 5, 4, 7, 2, 3, ~9, 7, ~7, 3, ~8, 7, 5, 5, ~2, ~6, ~3, 6, 5, 3, ~1, ~1, 4, 5, ~5, 5, 9, 9, 3, 8, ~3, ~1, 9, ~9, 6, ~7, 7, 4, 6, ~8, ~9, 0, ~3, ~2, ~7, 1, ~2, ~6, 7, 7, 7], | |
330 | [ 2, 9, 9, 3, ~4, 0, 9, 2, 5, 3, ~5, ~3, ~1, 1, 8, ~6, 2, ~4, ~8, ~7, ~8, 4, 5, 8, ~1, ~1, 7, 2, 5, 5, ~4, ~7, ~3, ~7, 6, ~4, ~5, ~8, ~5, ~9, ~8, 5, ~5, ~5, 0, 8, 8, 6, 4, ~1], | |
331 | [ 5, 5, 1, ~7, 3, ~5, 4, 9, 3, 4, 4, ~5, 7, ~1, 7, 4, ~7, 7, ~7, ~2, 9, ~9, 0, ~4, ~4, 0, 2, 6, 3, ~1, 6, 6, 8, ~6, ~4, ~9, 3, ~2, ~5, 5, ~3, 2, ~1, ~6, 9, 3, ~3, ~8, ~9, 7], | |
332 | [ 7, 1, 2, 7, 6, 5, ~6, ~3, ~4, ~8, 0, 9, 6, 1, 2, ~5, 4, 4, 4, ~6, ~7, ~9, ~6, 2, ~4, 5, ~2, 1, 0, 1, ~8, 7, ~7, ~5, 4, 1, ~5, 4, ~4, ~2, ~3, 1, 1, 3, 4, ~4, ~5, 9, 8, ~2], | |
333 | [ 6, 2, ~1, ~8, 4, ~7, 7, ~3, ~2, ~5, 3, 0, 3, ~9, 3, 3, 9, ~1, 4, 8, ~9, 6, ~5, 9, 5, ~1, ~1, ~9, 7, ~2, 3, 9, 8, 9, 2, 7, 7, 6, ~1, ~1, ~2, ~2, ~7, 3, ~6, 0, ~9, 4, 3, 7], | |
334 | [ 0, ~6, ~3, ~7, ~1, 5, ~2, 8, ~5, ~3, ~8, 7, ~2, ~2, 0, ~8, 4, 8, 9, ~5, ~4, ~8, ~1, 7, 1, 1, 6, ~9, ~4, 0, 8, 4, 3, ~7, 6, 0, 1, 8, 6, ~1, ~1, ~7, 9, ~9, ~5, ~2, ~2, ~1, 1, 0], | |
335 | [~4, 9, 6, ~3, ~2, ~6, ~3, 4, 8, ~8, 1, ~5, 9, 7, 9, 7, ~9, ~6, 6, 1, ~3, 3, ~3, ~7, 1, 7, ~7, 0, ~2, 7, ~4, ~6, 0, 1, ~3, ~5, ~9, ~7, 8, 4, 9, ~8, ~8, ~7, ~6, 7, 6, ~3, ~8, 5], | |
336 | [ 6, 7, ~5, ~9, 6, 1, 8, 4, ~2, 7, ~7, ~1, ~9, 1, ~6, ~5, 4, 9, 6, 0, ~8, ~3, 1, ~3, 8, ~3, 2, 9, ~3, ~9, ~1, ~3, 4, 3, 2, ~9, ~5, ~3, 8, ~4, 8, 5, ~4, 7, 6, ~8, 7, 6, ~5, 5], | |
337 | [ 1, 7, ~8, ~9, ~7, ~3, 8, 9, ~7, ~1, ~7, 4, 0, 0, 1, ~5, 9, ~8, ~1, ~2, 3, 5, 9, ~9, 5, 4, ~9, 1, ~4, ~2, 3, ~4, 8, ~6, ~4, ~8, ~5, ~5, 4, ~2, ~4, ~1, ~9, ~5, 2, ~9, 2, ~9, ~2, ~3], | |
338 | [~5, ~4, ~4, 9, 2, 7, ~2, 6, 7, 2, ~9, 4, 2, 7, 8, ~9, 2, 5, 3, 9, 6, 3, 0, ~7, ~6, ~7, 6, ~2, 9, ~3, ~6, 9, ~9, 2, 2, ~6, ~1, 4, ~3, 3, 0, 6, ~3, 4, 9, 9, ~6, 5, 5, ~5], | |
339 | [ 5, ~7, 8, ~4, 8, 8, ~4, ~9, 6, 0, ~3, 6, 0, 8, 8, ~6, ~2, 5, 4, ~1, ~8, 1, ~3, ~1, 2, 3, ~9, ~9, ~5, 1, 8, ~5, ~3, 0, ~4, ~9, 0, ~6, 3, ~1, ~7, 0, 8, 9, ~6, ~1, ~9, 1, ~6, 2], | |
340 | [ 7, ~5, ~1, 5, ~2, 7, 0, ~7, ~1, 8, 8, ~3, 9, ~5, 7, ~8, ~8, ~4, 3, 2, ~1, 8, ~2, 1, 2, 5, 0, ~6, 7, 3, 3, 7, ~5, 5, ~1, 1, 0, ~8, 1, 0, 0, ~4, 6, 9, ~5, ~6, 3, ~5, 8, 5], | |
341 | [~4, ~2, 3, ~3, ~1, 2, ~2, ~1, ~9, ~5, 1, 0, 0, 2, 9, ~3, ~9, 2, 9, 3, 8, ~3, 4, 8, 8, 3, ~3, ~1, ~4, 4, ~6, ~9, 5, ~2, 1, 3, ~7, ~5, ~6, ~5, ~8, 4, ~8, ~3, 5, 0, 7, ~9, 6, 2], | |
342 | [ 5, 1, 4, ~3, ~1, ~9, 5, ~8, ~8, 6, 1, 1, ~2, 7, 5, 6, ~4, 2, ~7, 0, ~7, ~3, ~5, 9, 3, 4, ~6, 8, ~4, 3, 6, 0, 2, 3, ~6, 3, 9, 4, 1, ~4, 6, ~5, ~7, 0, ~1, ~8, ~3, ~9, 9, 7], | |
343 | [ 2, ~6, ~1, 8, 4, ~3, ~1, ~6, ~2, ~8, ~2, ~1, ~1, ~5, ~9, ~8, 9, ~9, 5, 1, 9, ~1, ~6, 9, ~7, 2, 8, ~7, 4, ~9, 7, 6, ~2, 1, ~2, ~7, 8, 0, 5, 0, ~5, ~7, ~6, 0, 4, 0, 3, ~8, 5, 4], | |
344 | [~2, 9, ~9, ~6, 1, ~8, 8, 4, ~6, 8, 1, ~3, ~7, 8, ~5, 2, ~8, 1, 3, ~2, 6, 6, 6, 1, 0, 0, ~7, 7, ~3, ~3, 0, ~4, 3, ~7, ~6, 7, 5, 9, ~5, 7, ~8, 2, 3, ~8, ~7, 6, ~5, ~5, ~8, ~9], | |
345 | [~7, ~4, 4, 1, ~1, ~3, ~8, 3, 7, 9, 8, 3, 0, 4, 4, ~1, ~5, 4, 2, 2, 0, 6, ~6, 2, ~9, 8, ~9, 3, ~2, 2, 6, 6, 1, 7, 1, 0, ~8, 2, 3, ~3, 8, 9, 5, 5, ~6, 4, ~7, ~4, ~2, ~3], | |
346 | [~5, 8, 6, 1, ~6, ~6, 6, 1, 1, ~3, ~9, ~6, 2, ~7, 2, ~1, 6, ~6, 0, 2, ~7, 8, ~8, 4, 9, ~3, 9, ~7, ~9, ~6, ~4, ~4, ~5, 8, 2, ~5, ~4, ~3, 5, 2, 1, ~3, ~3, ~7, ~9, 3, 7, ~7, 3, ~8], | |
347 | [~4, ~7, ~2, 2, ~4, ~2, 6, ~3, ~1, ~4, 0, ~5, 9, 7, ~6, ~9, 7, ~9, ~6, 2, ~3, 1, 5, ~9, 4, ~5, 4, ~9, 1, ~2, ~2, 4, 0, 4, ~8, ~8, 3, ~1, ~5, ~4, ~9, ~7, 7, 6, 3, ~9, 6, 4, ~4, ~7], | |
348 | [~9, 6, 6, ~5, ~1, ~7, 4, ~9, 4, ~1, 6, ~4, 7, 2, 8, 7, 3, 1, ~7, 7, 7, 9, 8, ~9, 7, 2, 1, 2, ~8, 4, 5, 6, 7, 2, ~7, 6, 8, 4, ~9, 7, ~5, 6, 9, ~1, 9, 2, 0, 9, 3, 6], | |
349 | [ 4, ~3, 8, 0, ~2, ~2, 2, ~3, 8, 3, 1, ~8, ~5, ~2, 5, 6, 8, 0, ~3, 4, ~2, 4, ~9, ~5, 7, 6, ~4, ~7, 2, 4, ~3, ~8, ~9, 9, 8, ~9, 3, ~7, 4, ~7, ~5, 4, 9, 3, ~6, ~3, ~7, 4, 2, ~2], | |
350 | [~8, ~8, 6, ~2, ~6, 8, ~3, 3, ~1, ~7, 1, 9, 1, 7, ~6, 8, ~2, ~9, ~1, 3, ~4, 7, 8, ~1, 9, ~9, 6, ~3, 5, 0, 2, 5, ~1, ~6, ~6, 1, 8, 6, ~3, ~9, ~1, 9, ~2, 9, ~8, ~7, ~3, 6, ~3, ~3], | |
351 | [ 5, ~2, 3, 0, ~9, ~8, ~6, 1, 8, 0, 1, 2, ~8, ~2, 0, ~9, ~8, 0, 5, ~3, ~4, 5, 6, ~2, ~5, 0, ~9, 9, ~9, ~5, 9, 9, ~5, ~2, 4, 3, 8, ~8, ~7, 5, ~3, ~2, 2, 3, 9, 7, ~1, 0, 4, ~1], | |
352 | [~4, 5, ~5, 7, 8, 9, 7, ~3, 1, 9, ~7, ~1, 8, ~5, ~1, 2, ~8, 1, 0, 9, ~8, ~1, 6, ~1, 9, ~8, 7, 4, ~8, 7, 0, ~6, 2, 3, 7, 4, ~3, ~5, 9, ~3, 0, 6, ~9, 2, 4, ~8, 6, ~7, 9, 1], | |
353 | [ 7, 0, ~9, 6, 8, 2, 2, 5, ~6, ~6, 9, ~5, 9, 2, 2, ~8, 0, ~6, ~9, ~6, ~4, ~9, 8, ~2, 9, 7, ~5, ~1, 7, 2, ~7, 7, ~1, ~3, 6, 6, 1, ~4, 0, ~1, ~6, ~5, 6, ~7, ~3, ~2, 8, 2, ~9, 8], | |
354 | [ 8, ~7, ~9, ~6, 9, ~7, ~7, 6, ~8, 9, 5, ~4, 1, ~7, ~8, ~6, ~3, 8, ~8, 1, ~8, 6, 9, ~3, ~7, 7, 1, 6, 1, 0, 8, ~5, ~8, 8, ~9, 0, 4, 4, 3, ~4, 6, ~3, ~9, 0, 4, ~4, ~5, ~9, ~5, ~8], | |
355 | [~3, ~2, 8, 1, ~1, ~1, ~4, 3, 7, ~2, ~9, 9, ~8, ~9, 6, ~4, 7, ~1, ~5, ~3, ~9, 0, ~3, 0, 7, 9, 1, ~2, 7, ~9, ~6, 3, 3, ~4, ~7, ~3, ~4, ~8, ~2, ~3, ~9, ~2, ~6, 3, ~6, ~4, 7, ~5, ~8, ~1], | |
356 | [~9, ~9, ~2, ~9, ~9, 9, 6, 6, 7, 5, ~1, ~2, 1, 5, 2, ~3, ~4, 1, ~6, 0, ~3, ~9, ~1, 7, 0, ~9, 5, ~2, ~2, 5, 3, 4, ~1, 6, ~6, 3, ~6, 7, ~1, 5, ~8, ~4, ~2, ~2, ~6, ~5, ~6, 3, ~1, 4], | |
357 | [ 7, 7, 8, 7, 6, 1, ~2, 5, ~6, 9, 4, 8, 5, 0, ~4, ~2, ~2, ~5, ~2, ~6, 9, ~8, ~2, ~5, ~9, 3, ~6, ~3, ~4, ~5, ~2, 6, 1, 6, ~5, 0, ~3, ~2, 4, ~6, 1, 6, ~1, 3, ~9, 2, ~3, 1, 5, ~6], | |
358 | [ 6, 4, ~7, 3, ~7, 9, 1, ~7, ~8, 0, ~6, 8, 4, 1, 9, 6, 8, 3, 0, 9, 0, 4, 9, ~7, ~7, 1, 5, 1, ~5, 6, 9, 2, 4, 1, ~9, 8, 4, 5, 8, 3, 2, ~9, ~6, ~9, 9, ~9, 7, ~6, ~4, 3], | |
359 | [~3, ~9, ~4, 2, 3, 9, ~9, 8, ~9, 9, ~4, ~9, ~5, 5, 0, 7, 3, ~5, ~8, 2, ~3, 0, ~9, ~3, 1, 9, 4, 5, ~1, 8, 0, ~4, ~2, 9, ~4, ~1, 3, 5, 9, ~1, 1, 4, ~8, ~2, ~3, 5, 1, 5, ~6, 7], | |
360 | [ 9, ~3, 2, ~9, 3, 4, 0, 7, ~5, 9, 0, ~6, 7, ~2, 3, ~7, 2, ~5, ~2, 6, 3, ~9, ~5, ~9, 5, 2, ~5, ~3, 8, ~5, 6, 2, 9, ~7, ~7, ~7, ~6, 9, ~3, 6, 0, 6, ~6, ~9, 4, ~3, ~9, 0, ~4, ~9], | |
361 | [~4, ~8, 8, ~7, 7, 0, ~6, ~6, 8, ~9, ~4, 5, ~3, ~1, 7, ~5, ~6, ~1, 8, 6, ~2, 1, ~1, 5, ~9, 1, ~1, ~7, ~6, ~6, ~6, ~4, 6, 3, ~5, ~5, ~6, 2, 3, ~6, ~8, ~3, 8, ~2, ~5, ~4, ~3, 1, 4, ~4], | |
362 | [ 4, ~6, 2, 6, 2, ~8, 8, 5, 8, ~2, 0, ~6, ~1, ~6, ~2, 2, 6, ~9, ~7, ~6, ~4, ~4, ~7, ~2, 8, 6, 3, ~7, ~6, 8, 2, 3, 4, 5, 3, 4, ~6, 8, 8, ~1, 4, ~5, 6, 2, 8, ~3, ~9, ~2, 6, 7], | |
363 | [ 3, ~4, 0, ~3, ~5, 0, ~2, ~6, ~2, 8, 5, ~9, ~4, ~8, ~6, 0, 8, 9, 1, ~2, 8, 2, ~2, 8, 9, 3, 3, 5, ~9, ~3, ~2, 7, 2, 9, 0, 4, 8, ~9, 0, ~6, 9, ~9, 9, ~4, 8, ~8, ~8, 2, ~3, 2], | |
364 | [~1, 3, ~9, ~8, ~7, 6, ~6, 3, 0, 5, ~5, 1, 2, ~2, ~3, 7, 7, 3, ~4, ~2, ~9, ~5, ~1, 9, 6, 8, 2, 8, 7, ~3, 4, 6, 6, 0, ~2, 2, ~7, ~7, 6, ~3, 8, 2, 1, 0, 8, ~1, 3, 9, 8, 6], | |
365 | [ 1, ~2, ~3, 6, 5, 5, ~6, ~4, ~5, 1, 1, 6, ~7, ~4, ~3, 4, 4, ~8, ~9, 7, ~2, ~3, ~7, ~2, 1, 2, 0, 8, ~6, ~5, ~5, 7, 8, 5, ~2, 3, 9, 0, 5, 1, 3, ~4, ~6, 1, 4, ~9, ~2, 5, 4, 3], | |
366 | [ 3, 3, 9, ~2, 6, 9, 4, 9, 4, ~8, 5, ~1, 3, ~2, 1, ~7, ~3, 2, 2, 0, ~3, 3, 8, 2, 0, ~5, 7, 1, 4, ~8, 8, ~9, ~1, 1, ~9, ~4, 5, 2, 2, 8, 6, 1, 6, ~2, 2, 7, 1, ~6, ~1, ~1], | |
367 | [ 4, ~2, 4, ~1, ~5, ~1, 5, ~2, 3, ~4, ~5, 0, 2, ~4, 6, 4, ~3, 2, 2, 5, ~6, ~7, ~9, ~1, ~9, ~9, 6, 0, 6, 5, 9, ~1, 3, ~3, ~8, 8, ~8, 8, 4, 5, ~1, ~5, 1, 0, 3, ~2, 5, 6, 6, 5], | |
368 | [~4, 9, 6, 8, ~9, 5, 5, ~3, ~7, 7, 6, 8, ~8, 0, 4, ~1, 9, 5, ~7, 0, ~1, ~2, 3, 6, 0, 4, ~3, 1, 4, 6, 4, 0, 5, ~1, 7, ~7, ~6, ~8, ~3, ~6, 7, ~1, ~3, ~2, ~3, ~5, 3, 1, ~8, ~9], | |
369 | [~6, 4, ~5, 9, 9, ~7, ~1, ~8, ~4, 2, ~6, 0, ~6, ~6, 7, 6, 0, 1, 7, ~7, 0, ~4, ~6, ~8, ~9, 5, ~6, ~9, 2, ~7, ~2, ~6, 9, 4, ~5, 0, 4, ~4, ~5, 6, 9, 1, ~6, ~5, 3, ~1, 7, ~7, ~6, 7], | |
370 | [~8, 7, 7, ~6, 7, ~4, 8, 0, ~9, ~8, ~3, 7, ~3, 3, 8, ~7, ~2, ~7, 5, 5, ~5, 4, 6, 2, 4, 1, 4, ~9, ~3, 8, 8, ~9, ~4, ~2, 1, ~3, 1, 3, 9, ~5, ~8, ~2, 7, 8, 9, 2, 0, 1, ~9, 6], | |
371 | [~7, 1, ~9, 5, ~5, ~5, 7, 6, ~5, ~9, ~6, ~8, ~6, 9, 7, 9, 0, ~5, 7, 7, ~6, 4, 5, ~9, ~1, ~2, ~7, 3, ~5, ~2, ~5, 5, ~3, ~4, ~2, ~8, 2, ~8, 0, ~8, 0, ~8, 9, 8, ~5, ~5, 1, 3, 5, ~4], | |
372 | [~8, ~8, 0, ~5, ~8, ~6, 3, ~6, ~4, 6, 1, ~5, ~6, ~8, ~4, ~6, ~2, ~6, 6, ~4, 8, 8, 4, ~5, ~1, 0, 9, ~8, ~3, ~1, ~8, 7, ~3, 0, ~7, 1, ~7, ~1, ~7, 3, ~7, 3, ~4, ~8, 8, ~7, ~9, ~8, 3, 2], | |
373 | [ 3, 6, 8, ~9, 7, 1, ~9, 9, 3, 8, 6, 4, ~2, 1, ~8, 4, ~7, ~4, ~3, 3, ~5, ~6, ~7, ~2, 0, ~4, 5, 2, 5, 6, 3, ~8, 2, ~5, ~7, 6, 8, ~2, ~5, ~4, 9, 9, 2, ~2, ~2, 7, 4, 4, ~2, 3], | |
374 | [ 6, 6, ~5, ~2, ~8, ~2, ~9, 0, 2, 4, ~6, ~9, 9, 0, ~8, ~3, ~1, ~2, ~1, 6, 8, 2, ~9, 5, ~2, 1, 7, ~6, 5, 1, ~1, 4, ~4, ~7, ~6, ~3, ~8, 2, 2, 5, 5, ~6, 5, 3, 3, 7, 4, 7, ~3, ~9], | |
375 | [~9, 6, ~4, 1, 3, ~8, ~8, ~8, ~1, 5, 1, 1, ~1, 6, 5, 1, ~1, 5, ~8, 8, ~7, ~5, ~1, ~1, 6, ~8, ~3, ~1, ~2, ~6, ~5, ~5, ~6, 0, 2, 2, 7, ~1, ~5, ~7, ~1, ~3, 7, 6, 0, 2, 4, ~5, 0, ~4]] | |
376 | ||
377 | fun f (x, y) = List.nth (List.nth (table, x), y) | |
378 | fun show m = print (Matrix.toString (m, IntInf.toString)) | |
379 | structure Main = | |
380 | struct | |
381 | fun snf() = | |
382 | let val dim = 35 | |
383 | val big = Matrix.map (Matrix.make (dim, dim, f), IntInf.fromInt) | |
384 | val entry = Matrix.fetch(smithNormalForm big, dim - 1, dim - 1) | |
385 | (* val _ = print (concat [IntInf.toString entry, "\n"]) *) | |
386 | in if entry = valOf (IntInf.fromString | |
387 | "~1027954043102083189860753402541358641712697245") | |
388 | then () | |
389 | else raise Fail "bug" | |
390 | end | |
391 | fun doit n = | |
392 | let | |
393 | val rec loop = | |
394 | fn 0 => () | |
395 | | n => (snf(); loop(n - 1)) | |
396 | in loop n | |
397 | end | |
398 | end |