00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00018 #include "config.hpp"
00019
00020 #if !defined(ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE) || \
00021 defined(ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE_smith)
00022
00023 #include <cstddef>
00024
00025 #include "exception.hpp"
00026 #include "std_import.hpp"
00027 #include "factory.hpp"
00028 #include "cmp.hpp"
00029 #include "intalg.hpp"
00030 #include "gcd.hpp"
00031 #include "powerest.hpp"
00032 #include "vector.hpp"
00033 #include "matrix.hpp"
00034
00035 #include "smith.hpp"
00036
00037
00038 namespace Arageli
00039 {
00040
00041
00042 namespace _Internal
00043 {
00044
00045
00046 template <typename M>
00047 bool find_pivot_item
00048 (const M& B, std::size_t corner, std::size_t& min_i, std::size_t& min_j)
00049 {
00050 typedef typename M::element_type T;
00051 T min = null<T>();
00052
00053 for(std::size_t i = corner; i < B.nrows(); i++)
00054 for(std::size_t j = corner; j < B.ncols(); j++)
00055 if(!is_null(B(i, j)) && (is_null(min) || std::abs(B(i, j)) < min))
00056 {
00057 min = std::abs(B(i, j));
00058 min_i = i;
00059 min_j = j;
00060 }
00061
00062 return !is_null(min);
00063 }
00064
00065
00066 template <typename M>
00067 std::size_t find_pivot_item_in_row
00068 (const M& B, std::size_t corner, std::size_t i)
00069 {
00070 typedef typename M::element_type T;
00071 T min = null<T>();
00072 std::size_t min_j = 0;
00073
00074 for(std::size_t j = corner; j < B.ncols(); j++)
00075 if(!is_null(B(i, j)) && (is_null(min) || std::abs(B(i, j)) < min))
00076 {
00077 min = std::abs(B(i, j));
00078 min_j = j;
00079 }
00080
00081 return min_j;
00082 }
00083
00084
00085 template <typename M>
00086 std::size_t find_pivot_item_in_col
00087 (const M& B, std::size_t corner, std::size_t j)
00088 {
00089 typedef typename M::element_type T;
00090 T min = null<T>();
00091 std::size_t min_i = 0;
00092
00093 for(std::size_t i = corner; i < B.nrows(); i++)
00094 if(!is_null(B(i, j)) && (is_null(min) || std::abs(B(i, j)) < min))
00095 {
00096 min = std::abs(B(i, j));
00097 min_i = i;
00098 }
00099
00100 return min_i;
00101 }
00102
00103
00104 template <typename M>
00105 bool find_non_divisor_of_item
00106 (
00107 const M& B,
00108 std::size_t corner,
00109 typename M::element_type item,
00110 std::size_t& k, std::size_t& l
00111 )
00112 {
00113 for(std::size_t i = corner; i < B.nrows(); i++)
00114 for(std::size_t j = corner; j < B.ncols(); j++)
00115 if(!is_null(B(i, j) % item))
00116 {
00117 k = i;
00118 l = j;
00119 return true;
00120 }
00121
00122 return false;
00123 }
00124
00125
00126 }
00127
00128
00129 template
00130 <
00131 typename MA,
00132 typename MB,
00133 typename MP,
00134 typename MQ,
00135 typename Rank,
00136 typename T_det, typename T_factory,
00137 typename Ctrler, typename Norm
00138 >
00139 void smith
00140 (
00141 const MA& A,
00142 MB& B,
00143 MP& P,
00144 MQ& Q,
00145 Rank& rank,
00146 T_det& det,
00147 const T_factory& tfctr,
00148 Ctrler ctrler,
00149 Norm norm
00150 )
00151 {
00152 typedef typename MB::element_type T_B;
00153
00154 det = tfctr.unit(det);
00155 std::size_t m = A.nrows();
00156 std::size_t n = A.ncols();
00157 Q.assign_eye(n);
00158 P.assign_eye(m);
00159 B = A;
00160
00161 ctrler.preamble();
00162 ctrler.current_matrices(Q, B, P);
00163
00164 for(std::size_t corner = 0; corner < m && corner < n; corner++)
00165 {
00166 std::size_t new_i, new_j, i, j;
00167 T_B pivot_item;
00168
00169 if(!_Internal::find_pivot_item(B, corner, new_i, new_j))
00170
00171 break;
00172
00173 ctrler.find_smallest_nonzero(new_i, new_j);
00174
00175 for(;;)
00176 {
00177 if(ctrler.stop(corner, new_i, new_j, Q, B, P))
00178 {
00179 ctrler.conclusion();
00180 return;
00181 }
00182
00183 do
00184 {
00185 i = new_i;
00186 j = new_j;
00187 pivot_item = B(i, j);
00188
00189 ctrler.pivot_item(i, j);
00190
00191 for(std::size_t jj = 0; jj < n; jj++)
00192 if(jj != j)
00193 {
00194 T_B p = B(i, jj) / pivot_item;
00195 B.addmult_cols(jj, j, -p);
00196 Q.addmult_cols(jj, j, -p);
00197 }
00198
00199 for(std::size_t ii = 0; ii < m; ii++)
00200 if(ii != i)
00201 {
00202 T_B p = B(ii, j) / pivot_item;
00203 B.addmult_rows(ii, i, -p);
00204 P.addmult_rows(ii, i, -p);
00205 }
00206
00207
00208 ctrler.after_pivoting();
00209 ctrler.current_matrices(Q, B, P);
00210
00211 new_j = _Internal::find_pivot_item_in_row(B, corner, i);
00212
00213 if(new_j == j)
00214 new_i = _Internal::find_pivot_item_in_col(B, corner, j);
00215 else
00216 new_i = i;
00217 }while (i != new_i || j != new_j);
00218
00219
00220
00221 std::size_t k, l;
00222 if(!_Internal::find_non_divisor_of_item(B, corner, pivot_item, k, l))break;
00223
00224 B.add_rows(i, k);
00225 P.add_rows(i, k);
00226
00227 ctrler.nondivisor_entry(k, i, l);
00228 ctrler.current_matrices(Q, B, P);
00229 }
00230
00231 bool if_alter = false;
00232
00233 if(i != corner)
00234 {
00235 B.swap_rows(i, corner);
00236 P.swap_rows(i, corner);
00237 opposite(&det);
00238 if_alter = true;
00239 }
00240
00241 if(j != corner)
00242 {
00243 B.swap_cols(j, corner);
00244 Q.swap_cols(j, corner);
00245 opposite(&det);
00246 if_alter = true;
00247 }
00248
00249 if(is_negative(B(corner, corner)))
00250 {
00251 B.mult_row(corner, -1);
00252 P.mult_row(corner, -1);
00253 opposite(&det);
00254 if_alter = true;
00255 }
00256
00257 if(if_alter)
00258 {
00259 ctrler.pivot_adjustment();
00260 ctrler.current_matrices(Q, B, P);
00261 }
00262
00263 }
00264
00265 rank = 0;
00266
00267 for(std::size_t i = 0; i < m && i < n; i++)
00268 if(!is_null(B(i, i)))
00269 {
00270 det *= B(i, i);
00271 norm(B(i, i), P, i);
00272
00273
00274 rank++;
00275 }
00276 else break;
00277
00278 ctrler.conclusion();
00279 }
00280
00281
00282 template <typename M>
00283 M smith (const M& a)
00284 {
00285 typedef typename M::element_type T;
00286
00287 M b;
00288 matrix<T, false> p, q;
00289 T det;
00290 typename M::size_type rank;
00291 smith(a, b, p, q, rank, det);
00292 return b;
00293 }
00294
00295
00296 template
00297 <
00298 typename MA,
00299 typename MB,
00300 typename MP,
00301 typename MQ,
00302 typename Rank,
00303 typename T_det
00304 >
00305 void smith_storjohann
00306 (
00307 const MA &A,
00308 MB &B,
00309 MP &P,
00310 MQ &Q,
00311 Rank &rank,
00312 T_det &det
00313 )
00314 {
00315 typedef typename MA::element_type T_A;
00316
00317 matrix<T_A, false> U, E, F;
00318 smith_storjohann(A, P, Q, U, E, F, rank, det);
00319
00320
00321
00322 B = E*(U*(P*A*Q))*F;
00323 P = E*U*P;
00324 Q = Q*F;
00325 }
00326
00327
00328 template
00329 <
00330 typename MA,
00331 typename MB,
00332 typename MP,
00333 typename MQ,
00334 typename Rank,
00335 typename T_det
00336 >
00337 void smith_near_optimal
00338 (
00339 const MA &A,
00340 MB &B,
00341 MP &P,
00342 MQ &Q,
00343 Rank &rank,
00344 T_det &det
00345 )
00346 {
00347 typedef typename MA::element_type T_A;
00348
00349 matrix<T_A, false> U, V;
00350 smith_near_optimal(A, B, P, Q, U, V, rank, det);
00351 P = U*P;
00352 Q = Q*V;
00353 }
00354
00355
00356 }
00357
00358
00359 #if ARAGELI_DEBUG_LEVEL > 3
00360
00361 #include "big_int.hpp"
00362
00363 namespace Arageli
00364 {
00365
00366
00367 template void smith_storjohann
00368 (
00369 const matrix<big_int> &A,
00370 matrix<big_int> &B,
00371 matrix<big_int> &P,
00372 matrix<big_int>& Q,
00373 big_int &rank,
00374 big_int &det
00375 );
00376
00377 template void smith_storjohann
00378 (
00379 const matrix<int> &A,
00380 matrix<int> &B,
00381 matrix<int> &P,
00382 matrix<int>& Q,
00383 int &rank,
00384 int &det
00385 );
00386
00387
00388 template void smith_near_optimal
00389 (
00390 const matrix<big_int> &A,
00391 matrix<big_int> &B,
00392 matrix<big_int> &P,
00393 matrix<big_int>& Q,
00394 big_int &rank,
00395 big_int &det
00396 );
00397
00398 template void smith_near_optimal
00399 (
00400 const matrix<int> &A,
00401 matrix<int> &B,
00402 matrix<int> &P,
00403 matrix<int>& Q,
00404 int &rank,
00405 int &det
00406 );
00407
00408
00409 template void smith
00410 (
00411 const matrix<big_int> &A,
00412 matrix<big_int> &B,
00413 matrix<big_int> &P,
00414 matrix<big_int>& Q,
00415 big_int &rank,
00416 big_int &det
00417 );
00418
00419 template void smith
00420 (
00421 const matrix<int> &A,
00422 matrix<int> &B,
00423 matrix<int> &P,
00424 matrix<int>& Q,
00425 int &rank,
00426 int &det
00427 );
00428
00429
00430 }
00431
00432 #endif
00433
00434
00435
00436 #endif // #if !defined(ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE) || ...