1
(************************************************************************)
2
(* This file is part of SKS. SKS is free software; you can
3
redistribute it and/or modify it under the terms of the GNU General
4
Public License as published by the Free Software Foundation; either
5
version 2 of the License, or (at your option) any later version.
7
This program is distributed in the hope that it will be useful, but
8
WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
1
(***********************************************************************)
4
(* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, *)
5
(* 2011, 2012 Yaron Minsky and Contributors *)
7
(* This file is part of SKS. SKS is free software; you can *)
8
(* redistribute it and/or modify it under the terms of the GNU General *)
9
(* Public License as published by the Free Software Foundation; either *)
10
(* version 2 of the License, or (at your option) any later version. *)
12
(* This program is distributed in the hope that it will be useful, but *)
13
(* WITHOUT ANY WARRANTY; without even the implied warranty of *)
14
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *)
15
(* General Public License for more details. *)
17
(* You should have received a copy of the GNU General Public License *)
18
(* along with this program; if not, write to the Free Software *)
19
(* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *)
20
(* USA or see <http://www.gnu.org/licenses/>. *)
16
21
(***********************************************************************)
41
46
(*********************************************************************)
42
47
(*********************************************************************)
43
48
(*********************************************************************)
48
53
type t = { columns: int;
53
58
let columns m = m.columns
54
59
let rows m = m.rows
55
60
let dims t = (t.columns,t.rows)
57
62
let copy m = { m with array = Array.copy m.array; }
59
let make ~columns ~rows init =
64
let make ~columns ~rows init =
60
65
let array = Array.create (columns * rows) init in
61
66
{ columns = columns;
66
let init ~columns ~rows ~f =
71
let init ~columns ~rows ~f =
67
72
{ columns = columns;
70
Array.init (columns * rows)
72
let (i,j) = i mod columns, i / columns in
75
Array.init (columns * rows)
77
let (i,j) = i mod columns, i / columns in
77
82
m.array.(i + j * m.columns)
80
85
m.array.(i + j * m.columns) <- v
83
88
for i = 0 to Array.length m.array - 1 do
84
89
m.array.(i) <- ZZp.mult m.array.(i) sc
89
array = Array.map ~f:(fun x -> ZZp.mult v x) m.array
94
array = Array.map ~f:(fun x -> ZZp.mult v x) m.array
92
97
let scmult_row m j sc =
95
100
m.array.(start + i) <- ZZp.mult m.array.(start + i) sc
98
let swap_rows m j1 j2 =
99
let start1 = j1 * m.columns
103
let swap_rows m j1 j2 =
104
let start1 = j1 * m.columns
100
105
and start2 = j2 * m.columns in
103
let tmp = m.array.(start1 + i) in
104
m.array.(start1 + i) <- m.array.(start2 + i);
105
m.array.(start2 + i) <- tmp)
108
let tmp = m.array.(start1 + i) in
109
m.array.(start1 + i) <- m.array.(start2 + i);
110
m.array.(start2 + i) <- tmp)
108
113
if m1.columns <> m2.columns || m1.rows <> m2.rows then
109
114
raise LayoutMismatch;
110
115
for i = 0 to Array.length m1.array - 1 do
111
116
m1.array.(i) <- ZZp.add m1.array.(i) m2.array.(i)
115
120
if m1.columns <> m2.columns || m1.rows <> m2.rows then
116
121
raise LayoutMismatch;
118
array = Array.init (m1.columns * m1.rows)
119
~f:(fun i -> ZZp.add m1.array.(i) m2.array.(i))
123
array = Array.init (m1.columns * m1.rows)
124
~f:(fun i -> ZZp.add m1.array.(i) m2.array.(i))
122
let rec idot_rec m1 m2 ~i ~pos1 ~pos2 sum =
127
let rec idot_rec m1 m2 ~i ~pos1 ~pos2 sum =
123
128
if i >= m1.columns then sum
125
130
idot_rec m1 m2 ~i:(i+1) ~pos1:(pos1 + 1) ~pos2:(pos2 + m2.columns)
126
(ZZp.add sum (ZZp.mult m1.array.(pos1) m2.array.(pos2)))
131
(ZZp.add sum (ZZp.mult m1.array.(pos1) m2.array.(pos2)))
129
134
idot_rec m1 m2 ~i:0 ~pos1:(m1.columns * i) ~pos2:j ZZp.zero
132
137
if m1.columns <> m2.rows then
133
138
raise LayoutMismatch;
134
139
init ~columns:m2.columns ~rows:m1.rows
135
140
~f:(fun i j -> idot m1 m2 i j)
139
144
init ~columns:m.rows ~rows:m.columns ~f:(fun i j -> get m j i)
142
let rowadd m ~src ~dst ~scmult =
147
let rowadd m ~src ~dst ~scmult =
143
148
for i = 0 to m.columns - 1 do
144
149
let newval = ZZp.add (ZZp.mult (get m i src) scmult) (get m i dst) in
145
150
set m i dst newval
148
let rowsub m ~src ~dst ~scmult =
153
let rowsub m ~src ~dst ~scmult =
149
154
if scmult <>: ZZp.one then
150
155
for i = 0 to m.columns - 1 do
151
let sval = get m i src in
152
if sval <>: ZZp.zero then
153
let newval = ZZp.sub (get m i dst) (ZZp.mult_fast sval scmult) in
156
let sval = get m i src in
157
if sval <>: ZZp.zero then
158
let newval = ZZp.sub (get m i dst) (ZZp.mult_fast sval scmult) in
157
162
for i = 0 to m.columns - 1 do
158
let sval = get m i src in
159
if sval <>: ZZp.zero then
160
let newval = ZZp.sub (get m i dst) sval in
163
let sval = get m i src in
164
if sval <>: ZZp.zero then
165
let newval = ZZp.sub (get m i dst) sval in
165
170
for j = 0 to m.rows - 1 do
166
171
print_string "| ";
167
172
for i = 0 to m.columns - 1 do
168
ZZp.print (get m i j);
173
ZZp.print (get m i j);
171
176
print_string " |\n"
178
183
(*********************************************************************************)
180
185
(* Does everything in-place, using the in-place numerix operators *)
184
189
type t = { columns: int;
186
array: ZZp.zzref array;
191
array: ZZp.zzref array;
189
194
let columns m = m.columns
190
195
let rows m = m.rows
191
196
let dims t = (t.columns,t.rows)
193
198
let copy m = { m with array = Array.copy m.array; }
195
let init ~columns ~rows ~f =
200
let init ~columns ~rows ~f =
196
201
{ columns = columns;
199
Array.init (columns * rows)
201
let (i,j) = i mod columns, i / columns in
202
ZZp.make_ref (f i j))
204
Array.init (columns * rows)
206
let (i,j) = i mod columns, i / columns in
207
ZZp.make_ref (f i j))
205
let make ~columns ~rows x =
210
let make ~columns ~rows x =
206
211
init ~columns ~rows ~f:(fun i j -> x)
209
214
ZZp.look (m.array.(i + j * m.columns))
212
217
m.array.(i + j * m.columns)
214
219
let get m i j = ZZp.copy_out m.array.(i + j * m.columns)
217
222
ZZp.copy_in m.array.(i + j * m.columns) v
219
224
let scmult_row ?(scol=0) m j sc =
223
228
ZZp.mult_in v (ZZp.look v) sc
226
let swap_rows m j1 j2 =
227
let start1 = j1 * m.columns
231
let swap_rows m j1 j2 =
232
let start1 = j1 * m.columns
228
233
and start2 = j2 * m.columns in
231
let tmp = ZZp.copy_out m.array.(start1 + i) in
232
ZZp.copy_in m.array.(start1 + i) (ZZp.look m.array.(start2 + i));
233
ZZp.copy_in m.array.(start2 + i) tmp)
236
let tmp = ZZp.copy_out m.array.(start1 + i) in
237
ZZp.copy_in m.array.(start1 + i) (ZZp.look m.array.(start2 + i));
238
ZZp.copy_in m.array.(start2 + i) tmp)
236
241
init ~columns:m.rows ~rows:m.columns ~f:(fun i j -> lget m j i)
238
let rowsub ?(scol=0) m ~src ~dst ~scmult =
243
let rowsub ?(scol=0) m ~src ~dst ~scmult =
239
244
if scmult <>: ZZp.one then
240
245
for i = scol to m.columns - 1 do
241
let sval = rget m i src in
242
if ZZp.look sval <>: ZZp.zero then
243
let v = rget m i dst in
244
ZZp.sub_in v (ZZp.look v) (ZZp.mult_fast (ZZp.look sval) scmult)
246
let sval = rget m i src in
247
if ZZp.look sval <>: ZZp.zero then
248
let v = rget m i dst in
249
ZZp.sub_in v (ZZp.look v) (ZZp.mult_fast (ZZp.look sval) scmult)
247
252
for i = scol to m.columns - 1 do
248
let sval = rget m i src in
249
if ZZp.look sval <>: ZZp.zero then
250
let v = rget m i dst in
251
ZZp.sub_in v (ZZp.look v) (ZZp.look sval)
253
let sval = rget m i src in
254
if ZZp.look sval <>: ZZp.zero then
255
let v = rget m i dst in
256
ZZp.sub_in v (ZZp.look v) (ZZp.look sval)
255
260
for j = 0 to m.rows - 1 do
256
261
print_string "| ";
257
262
for i = 0 to m.columns - 1 do
258
ZZp.print (lget m i j);
263
ZZp.print (lget m i j);
261
266
print_string " |\n"
271
276
(****** Gauss-Jordan Reduction *****************)
273
278
let process_row m j =
276
281
let v = Matrix.rget m j j in
277
282
if ZZp.look v <>: ZZp.zero then v
281
rfind (j + 1) (Matrix.rows m)
282
~f:(fun jswap -> Matrix.lget m j jswap <>: ZZp.zero)
283
with Not_found -> raise Exit
285
Matrix.swap_rows m j jswap;
286
rfind (j + 1) (Matrix.rows m)
287
~f:(fun jswap -> Matrix.lget m j jswap <>: ZZp.zero)
288
with Not_found -> raise Exit
290
Matrix.swap_rows m j jswap;
288
293
if ZZp.look v <>: ZZp.one then Matrix.scmult_row m j (ZZp.inv (ZZp.look v));
289
294
for j2 = 0 to Matrix.rows m - 1 do
291
296
then Matrix.rowsub m ~src:j ~dst:j2 ~scmult:(Matrix.get m j j2)
304
309
(****** Gaussian Reduction *****************)
306
311
let process_row_forward m j =
309
314
let v = Matrix.rget m j j in
310
315
if ZZp.look v <>: ZZp.zero then v
314
rfind (j + 1) (Matrix.rows m)
315
~f:(fun jswap -> Matrix.lget m j jswap <>: ZZp.zero)
316
with Not_found -> raise Exit
318
Matrix.swap_rows m j jswap;
319
rfind (j + 1) (Matrix.rows m)
320
~f:(fun jswap -> Matrix.lget m j jswap <>: ZZp.zero)
321
with Not_found -> raise Exit
323
Matrix.swap_rows m j jswap;
321
326
if ZZp.look v <>: ZZp.one then Matrix.scmult_row ~scol:j m j (ZZp.inv (ZZp.look v));
322
327
for j2 = j + 1 to Matrix.rows m - 1 do