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