1 /* tests/__LINBOX_smith_form_kannan_bachem.h
2  * Copyright (C) 2017 Gavin Harrison,
3  *
4  * Written by Gavin Harrison <gmh33@drexel.edu>,
5  *
6  * ========LICENCE========
7  * This file is part of the library LinBox.
8  *
9  * LinBox is free software: you can redistribute it and/or modify
10  * it under the terms of the  GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  * ========LICENCE========
23  *.
24  */
25 
26 #include <iostream>
27 #include "linbox/matrix/densematrix/blas-matrix.h"
28 #include "linbox/matrix/matrixdomain/matrix-domain.h"
29 
30 #ifndef __LINBOX_smith_form_kannan_bachem_domain_H
31 #define __LINBOX_smith_form_kannan_bachem_domain_H
32 
33 namespace LinBox
34 {
35 	template<class Field>
36 	class SmithFormKannanBachemDomain
37 	{
38 	public:
39 		typedef typename Field::Element Element;
40 
41 		typedef MatrixDomain<Field> MatrixDom;
42 
43 		typedef typename MatrixDom::OwnMatrix OwnMatrix;
44 		typedef typename MatrixDom::Matrix SubMatrix;
45 
46 	private:
47 		Field _F;
48 		MatrixDom _MD;
49 
50 	public:
SmithFormKannanBachemDomain(const Field & F)51 		SmithFormKannanBachemDomain(const Field &F) : _F(F), _MD(_F) {}
SmithFormKannanBachemDomain(const SmithFormKannanBachemDomain & D)52 		SmithFormKannanBachemDomain(const SmithFormKannanBachemDomain &D) : _F(D._F), _MD(D._MD) {}
53 
54 	private:
55 
56 		template<typename Matrix>
printMatrix(const Matrix & M)57 		void printMatrix(const Matrix &M) const {
58 			for (size_t i = 0; i < M.rowdim(); i++) {
59 				for (size_t j = 0; j < M.coldim(); j++) {
60 					_F.write(std::cout, M.getEntry(i, j)) << std::endl;
61 				}
62 				std::cout << std::endl;
63 			}
64 		}
65 
66 		template<typename Matrix>
swapRows(Matrix & M,size_t r1,size_t r2)67 		void swapRows(Matrix &M, size_t r1, size_t r2) const {
68 			SubMatrix row1(M, r1, 0, 1, M.coldim());
69 			SubMatrix row2(M, r2, 0, 1, M.coldim());
70 
71 			row1.swap(row2);
72 		}
73 
74 		template<typename Matrix>
swapCols(Matrix & M,size_t c1,size_t c2)75 		void swapCols(Matrix &M, size_t c1, size_t c2) const {
76 			SubMatrix col1(M, 0, c1, M.rowdim(), 1);
77 			SubMatrix col2(M, 0, c2, M.rowdim(), 1);
78 
79 			col1.swap(col2);
80 		}
81 
dxgcd(Element & s,Element & t,Element & u,Element & v,const Element & a,const Element & b)82 		void dxgcd(Element &s, Element &t, Element &u, Element &v, const Element &a, const Element &b) const {
83 			if (_F.isDivisor(b, a)) {
84 				_F.assign(s, _F.one);
85 				_F.assign(t, _F.zero);
86 				_F.assign(u, _F.one);
87 				_F.div(v, b, a);
88 				return;
89 			}
90 
91 			Element g;
92 
93             _F.gcd(g,s,t,a,b);
94             _F.div(u,a,g);
95             _F.div(v,b,g);
96 		}
97 
98 		template<class Matrix>
findPivot(Matrix & A)99 		bool findPivot(Matrix &A) {
100 			for (size_t i = 0; i < A.rowdim(); i++) {
101 				for (size_t j = 0; j < A.coldim(); j++) {
102 					if (_F.isZero(A.getEntry(i, j))) {
103 						continue;
104 					}
105 
106 					if (i > 0) {
107 						swapRows(A, 0, i);
108 					}
109 
110 					if (j > 0) {
111 						swapCols(A, 0, j);
112 					}
113 
114 					return true;
115 				}
116 			}
117 
118 			return false;
119 		}
120 
121 		template<class Matrix>
eliminateRow1(Matrix & A,size_t idx)122 		void eliminateRow1(Matrix &A, size_t idx) {
123 			Element pivot, other;
124 
125 			A.getEntry(other, 0, idx);
126 
127 			if (_F.isZero(other)) {
128 				return;
129 			}
130 
131 			A.getEntry(pivot, 0, 0);
132 
133 			Element s, t, u, v;
134 			dxgcd(s,t,u,v,pivot,other);
135 			_F.negin(v);
136 
137 			SubMatrix pivotCol(A, 0, 0, A.rowdim(), 1);
138 			SubMatrix otherCol(A, 0, idx, A.rowdim(), 1);
139 
140 			OwnMatrix pivotCopy(pivotCol);
141 
142 			_MD.mulin(pivotCol, s);
143 			_MD.saxpyin(pivotCol, t, otherCol);
144 
145 			_MD.mulin(otherCol, u);
146 			_MD.saxpyin(otherCol, v, pivotCopy);
147 		}
148 
149 		template<class Matrix>
eliminateRow(Matrix & A)150 		void eliminateRow(Matrix &A) {
151 			for (size_t i = 1; i < A.coldim(); i++) {
152 				eliminateRow1(A, i);
153 			}
154 		}
155 
156 		template<class Matrix>
zeroRow(Matrix & A)157 		void zeroRow(Matrix &A) {
158 			for (size_t i = 1; i < A.coldim(); i++) {
159 				A.setEntry(0, i, _F.zero);
160 			}
161 		}
162 
163 		template<class Matrix>
eliminateCol1(Matrix & A,size_t idx)164 		void eliminateCol1(Matrix &A, size_t idx) {
165 			Element pivot, other;
166 
167 			A.getEntry(other, idx, 0);
168 
169 			if (_F.isZero(other)) {
170 				return;
171 			}
172 
173 			A.getEntry(pivot, 0, 0);
174 
175 			Element s, t, u, v;
176 			dxgcd(s,t,u,v,pivot,other);
177 			_F.negin(v);
178 
179 			SubMatrix pivotRow(A, 0, 0, 1, A.coldim());
180 			SubMatrix otherRow(A, idx, 0, 1, A.coldim());
181 
182 			OwnMatrix pivotCopy(pivotRow);
183 
184 			_MD.mulin(pivotRow, s);
185 			_MD.saxpyin(pivotRow, t, otherRow);
186 
187 			_MD.mulin(otherRow, u);
188 			_MD.saxpyin(otherRow, v, pivotCopy);
189 		}
190 
191 		template<class Matrix>
eliminateCol(Matrix & A)192 		void eliminateCol(Matrix &A) {
193 			for (size_t i = 1; i < A.rowdim(); i++) {
194 				eliminateCol1(A, i);
195 			}
196 		}
197 
198 		template<class Matrix>
isDiagonalized(Matrix & A)199 		bool isDiagonalized(Matrix &A) {
200 			for (size_t i = 1; i < A.rowdim(); i++) {
201 				if (!_F.isZero(A.getEntry(i, 0))) {
202 					return false;
203 				}
204 			}
205 
206 			for (size_t i = 1; i < A.coldim(); i++) {
207 				if (!_F.isZero(A.getEntry(0, i))) {
208 					return false;
209 				}
210 			}
211 
212 			return true;
213 		}
214 
fixDiagonalHelper(std::vector<Element> & v)215 		bool fixDiagonalHelper(std::vector<Element> &v) const {
216 			bool stable = true;
217 
218 			for (size_t i = 0; i < v.size() - 1 && !_F.isZero(v[i+1]); i++) {
219 				if (_F.isOne(v[i]) || _F.areEqual(v[i], v[i+1])) {
220 					continue;
221 				}
222 
223 				Element g, q;
224 				_F.gcd(g, v[i], v[i+1]);
225 
226 				if (_F.areEqual(g, v[i])) {
227 					continue;
228 				}
229 				stable = false;
230 
231 				_F.div(q, v[i], g);
232 
233 				_F.assign(v[i], g);
234 				_F.mulin(v[i+1], q);
235 			}
236 
237 			return stable;
238 		}
239 
fixDiagonal(std::vector<Element> & v)240 		void fixDiagonal(std::vector<Element> &v) {
241 			while (!fixDiagonalHelper(v));
242 		}
243 
fixDiagonal(std::vector<Element> & v,const Element & det)244 		void fixDiagonal(std::vector<Element> &v, const Element &det) {
245 			fixDiagonal(v);
246 
247 			for (size_t i = 0; i < v.size(); i++) {
248 				_F.remin(v[i], det);
249 			}
250 		}
251 
252 		template<class Matrix>
reduceOffDiagonal(Matrix & A)253 		void reduceOffDiagonal(Matrix &A) {
254 			size_t dim = A.rowdim() < A.coldim() ? A.rowdim() : A.coldim();
255 
256 			for (size_t i = 1; i < dim; i++) {
257 				Element pivot, other;
258 				A.getEntry(pivot, i, i);
259 				A.getEntry(other, 0, i);
260 
261 				if (_F.isZero(other)) {
262 					continue;
263 				}
264 
265 				Element q;
266 				_F.div(q, other, pivot);
267 
268 				if (_F.isZero(q)) {
269 					continue;
270 				}
271 
272 				_F.negin(q);
273 
274 				SubMatrix pivotRow(A, i, i, 1, A.coldim() - i);
275 				SubMatrix otherRow(A, 0, i, 1, A.coldim() - i);
276 
277 				_MD.saxpyin(otherRow, q, pivotRow);
278 			}
279 		}
280 
281 		template<class Matrix>
hermite(Matrix & A)282 		void hermite(Matrix &A) {
283 			if (A.rowdim() == 0 || A.coldim() == 0) {
284 				return;
285 			}
286 
287 			if (!findPivot(A)) {
288 				return;
289 			}
290 
291 			eliminateCol(A);
292 			SubMatrix B(A, 1, 1, A.rowdim() - 1, A.coldim() - 1);
293 			hermite(B);
294 			reduceOffDiagonal(A);
295 		}
296 
297 		template<class Matrix>
solveHelper(std::vector<Element> & L,Matrix & A)298 		void solveHelper(std::vector<Element> &L, Matrix &A) {
299 			if (A.rowdim() == 0 || A.coldim() == 0) {
300 				return;
301 			}
302 
303 			if (!findPivot(A)) {
304 				size_t dim = A.rowdim() < A.coldim() ? A.rowdim() : A.coldim();
305 				for (size_t i = 0; i < dim; i++) {
306 					L.push_back(_F.zero);
307 				}
308 				return;
309 			}
310 
311 			while (!isDiagonalized(A)) {
312 				eliminateRow(A);
313 				hermite(A);
314 			}
315 
316 			L.push_back(A.getEntry(0, 0));
317 			SubMatrix B(A, 1, 1, A.rowdim() - 1, A.coldim() - 1);
318 			solveHelper(L, B);
319 		}
320 
321 		template<class Matrix>
solveTextBookHelper(std::vector<Element> & L,Matrix & A)322 		void solveTextBookHelper(std::vector<Element> &L, Matrix &A) {
323 			if (A.rowdim() == 0 || A.coldim() == 0) {
324 				return;
325 			}
326 
327 			if (!findPivot(A)) {
328 				size_t dim = A.rowdim() < A.coldim() ? A.rowdim() : A.coldim();
329 				for (size_t i = 0; i < dim; i++) {
330 					L.push_back(_F.zero);
331 				}
332 				return;
333 			}
334 
335 			while (!isDiagonalized(A)) {
336 				eliminateCol(A);
337 				if (_F.isUnit(A.getEntry(0, 0))) {
338 					break;
339 				}
340 				eliminateRow(A);
341 			}
342 
343 			L.push_back(A.getEntry(0, 0));
344 			SubMatrix B(A, 1, 1, A.rowdim() - 1, A.coldim() - 1);
345 			solveTextBookHelper(L, B);
346 		}
347 
348 		// Iliopoulos Specific Methods
349 
350 		template<class Matrix>
reduceMatrix(Matrix & A,const Element & d)351 		void reduceMatrix(Matrix &A, const Element &d) {
352 			for (size_t i = 0; i < A.rowdim(); i++) {
353 				for (size_t j = 0; j < A.coldim(); j++) {
354 					Element tmp;
355 					A.getEntry(tmp, i, j);
356 					_F.modin(tmp, d);
357 					A.setEntry(i, j, tmp);
358 				}
359 			}
360 		}
361 
362 		template<class Matrix>
solveIliopoulosHelper(std::vector<Element> & L,Matrix & A,const Element & d)363 		void solveIliopoulosHelper(std::vector<Element> &L, Matrix &A, const Element &d) {
364 			if (A.rowdim() == 0 || A.coldim() == 0) {
365 				return;
366 			}
367 
368 			if (!findPivot(A)) {
369 				size_t dim = A.rowdim() < A.coldim() ? A.rowdim() : A.coldim();
370 				for (size_t i = 0; i < dim; i++) {
371 					L.push_back(_F.zero);
372 				}
373 				return;
374 			}
375 
376 			while (!isDiagonalized(A)) {
377 				eliminateCol(A);
378 				reduceMatrix(A, d);
379 
380 				eliminateRow(A);
381 				reduceMatrix(A, d);
382 			}
383 
384 			L.push_back(A.getEntry(0, 0));
385 			SubMatrix B(A, 1, 1, A.rowdim() - 1, A.coldim() - 1);
386 			solveIliopoulosHelper(L, B, d);
387 		}
388 
389 	public:
390 		template<class Matrix>
solve(std::vector<Element> & L,Matrix & A)391 		void solve(std::vector<Element> &L, Matrix &A) {
392 			solveHelper(L, A);
393 			fixDiagonal(L);
394 		}
395 
396 		template<class Matrix>
solveTextBook(std::vector<Element> & L,Matrix & A)397 		void solveTextBook(std::vector<Element> &L, Matrix &A) {
398 			solveTextBookHelper(L, A);
399 			fixDiagonal(L);
400 		}
401 
402 		template<class Matrix>
solveIliopoulos(std::vector<Element> & L,Matrix & A,const Element & d)403 		void solveIliopoulos(std::vector<Element> &L, Matrix &A, const Element &d) {
404 			reduceMatrix(A, d);
405 			solveIliopoulosHelper(L, A, d);
406 			fixDiagonal(L, d);
407 		}
408 	};
409 }
410 
411 #endif // __LINBOX_smith_form_kannan_bachem_domain_H
412 
413 // Local Variables:
414 // mode: C++
415 // tab-width: 4
416 // indent-tabs-mode: nil
417 // c-basic-offset: 4
418 // End:
419 // vim:sts=4:sw=4:ts=4:et:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s
420