00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #ifndef __MMX__MATRIX_RING_NAIVE__HPP
00014 #define __MMX__MATRIX_RING_NAIVE__HPP
00015 #include <algebramix/matrix_naive.hpp>
00016 #include <algebramix/polynomial.hpp>
00017 #include <algebramix/series.hpp>
00018
00019 namespace mmx {
00020 #define TMPL template<typename C>
00021
00022
00023
00024
00025
00026 template<typename V>
00027 struct matrix_ring_naive: public V {
00028 typedef typename V::Vec Vec;
00029 typedef matrix_ring_naive<typename V::Naive> Naive;
00030 typedef matrix_ring_naive<typename V::Positive> Positive;
00031 typedef matrix_ring_naive<typename V::No_simd> No_simd;
00032 typedef matrix_ring_naive<typename V::No_thread> No_thread;
00033 typedef matrix_ring_naive<typename V::No_scaled> No_scaled;
00034 };
00035
00036 template<typename F, typename V, typename W>
00037 struct implementation<F,V,matrix_ring_naive<W> >:
00038 public implementation<F,V,W> {};
00039
00040 template<typename C, typename V>
00041 struct matrix_variant_helper<polynomial<C,V> > {
00042 typedef matrix_ring_naive<matrix_naive> MV;
00043 };
00044
00045 template<typename C, typename V>
00046 struct matrix_variant_helper<series<C,V> > {
00047 typedef matrix_ring_naive<matrix_naive> MV;
00048 };
00049
00050
00051
00052
00053
00054 template<typename V, typename W>
00055 struct implementation<matrix_echelon,V,matrix_ring_naive<W> >:
00056 public implementation<matrix_iterate,V>
00057 {
00058 typedef implementation<matrix_iterate,V> Mat;
00059
00060 private:
00061
00062 TMPL static void
00063 col_echelon (C* m, C* k, nat ri, nat ci, nat rf, nat cf,
00064 nat rm, nat cm, C& num, C& den, bool reduced, nat* permut)
00065 {
00066
00067
00068 VERIFY ((ri < rm) && (ci < cm) && (rf <= rm) && (cf <= cm), "out of range");
00069 ASSERT (reduced == false, "Reduced echelon form not available over a ring");
00070 num= C(1); den= C(1);
00071 if (permut != NULL) for (nat i= 0; i < cm; i++) permut[i]= i;
00072
00073
00074 nat i= ri, j= ci;
00075 nat best_index;
00076 C best_val= 0;
00077 for (i= ri; i<rf; i++) {
00078 best_index= cf;
00079 for (j= ci; j<cf; j++) {
00080 C next_val= Mat::entry (m, i, j, rm, cm);
00081 if (next_val != 0)
00082 if (best_index == cf || better_pivot (next_val, best_val)) {
00083 best_index= j;
00084 best_val= next_val;
00085 }
00086 }
00087 if (best_index != cf) { j= best_index; break; }
00088 }
00089
00090 if (i<rf && j<cf) {
00091
00092 if (j != ci) {
00093 if (k != NULL) Mat::col_swap (k, ci, j, cm, cm);
00094 Mat::col_swap (m, ci, j, rm, cm);
00095 if (permut != NULL) swap (permut[j], permut[ci]);
00096 den= -den;
00097 }
00098 ri= i;
00099
00100 C p= Mat::entry (m, ri, ci, rm, cm);
00101 num *= p;
00102 for (nat index = 1; index < cf-ci; index++) {
00103 den *= p;
00104 C t= Mat::entry (m, ri, ci + index, rm, cm);
00105 if (k != NULL) Mat::col_combine_sub (k, ci + index, p, ci, t, cm, cm);
00106 Mat::col_combine_sub (m, ci + index, p, ci, t, rm, cm);
00107 }
00108
00109 if (ri+1 < rf && ci+1 < cf) {
00110 C x, y;
00111 col_echelon (m, k, ri+1, ci+1, rf, cf, rm, cm, x, y, reduced, permut);
00112 num *= x; den *=y;
00113 }
00114 }
00115 }
00116
00117 public:
00118
00119 TMPL static inline void
00120 col_echelon (C* m, C* k, nat rm, nat cm, C& num, C& den,
00121 bool reduced= false, nat* permut= NULL) {
00122 if (k != NULL) Mat::set (k, C(1), cm, cm);
00123 col_echelon (m, k, 0, 0, rm, cm, rm, cm, num, den, reduced, permut);
00124 }
00125
00126 TMPL static inline void
00127 col_echelon (C* m, C* k, nat rm, nat cm,
00128 bool reduced= false, nat* permut= NULL) {
00129 if (k != NULL) Mat::set (k, C(1), cm, cm);
00130 C num, den;
00131 col_echelon (m, k, rm, cm, num, den, reduced, permut);
00132 }
00133
00134 };
00135
00136
00137
00138
00139
00140 template<typename V, typename W>
00141 struct implementation<matrix_determinant,V,matrix_ring_naive<W> >:
00142 public implementation<matrix_echelon,V>
00143 {
00144 typedef implementation<vector_linear,V> Vec;
00145 typedef implementation<matrix_echelon,V> Mat;
00146
00147 private:
00148
00149 TMPL static inline void
00150 berkowitz (C* d, const C* s, nat n) {
00151
00152
00153
00154
00155 if (n == 0) { d[0]= 1; return; }
00156 d[1]= 1;
00157 d[0]= - *(s + Mat::index (0, 0, n, n));
00158 if (n == 1) return;
00159 nat len_t= aligned_size<C,V> (n + 1);
00160 nat len_s= aligned_size<C,V> ((n-1) * (n-1));
00161 nat l= aligned_size<C,V> (n-1);
00162 C** t= mmx_new<C*> (len_t);
00163 C* buf= mmx_new<C> (3 * len_t + len_s + 2 * l);
00164 for (nat j = 0; j < len_t; j++) t[j]= buf + j;
00165 C* t1= buf + len_t, * t2= buf + 2 * len_t;
00166 C* loc_s= buf + 3 * len_t;
00167 C* x= buf + 3 * len_t + len_s, * y= buf + 3 * len_t + len_s + l;
00168 for (nat i = 1; i < n; i++) {
00169
00170
00171 Mat::get_range (loc_s, s, 0, 0, i, i, n, n);
00172 Mat::get_range (y, s, i, 0, i+1, i , n, n);
00173 Mat::get_range (x, s, 0, i, i , i+1, n, n);
00174 Mat::project_iterate_mul (t, y, loc_s, x, 1, i, i, i, i, 1, i);
00175 for (nat j = 0; j < i; j++) t1[j] = t[j][0];
00176 C a= * (s + Mat::index (i, i, n, n));
00177 Mat::mul (t2, t1, d + 1, 1, i, 1);
00178 t2[0] += a * d[0];
00179 for (nat j = 1; j < i; j++) {
00180 Mat::mul (t2 + j, t1, d + j + 1, 1, i - j, 1);
00181 t2[j] += a * d[j] - d[j-1];
00182 }
00183 t2[i] = a * d[i] - d[i-1];
00184 t2[i+1]= - d[i];
00185 Vec::neg (d, t2, i+2);
00186 }
00187 mmx_delete<C> (buf, 3 * len_t + len_s + 2 * l);
00188 mmx_delete<C*> (t, len_t);
00189 }
00190
00191 public:
00192
00193 TMPL static inline void
00194 det (C& r, const C* s, nat n) {
00195 nat l= default_aligned_size<C> (n + 1);
00196 C* d= mmx_new<C> (l);
00197 berkowitz (d, s, n);
00198
00199
00200 r= (n & 1) ? - d[0] : d[0];
00201 mmx_delete<C> (d, l);
00202 }
00203
00204 TMPL static inline void
00205 characteristic_polynomial (C* d, const C* s, nat n) {
00206 berkowitz (d, s, n);
00207 }
00208
00209 };
00210
00211
00212
00213
00214
00215 template<typename V, typename W>
00216 struct implementation<matrix_kernel,V,matrix_ring_naive<W> >:
00217 public implementation<matrix_echelon,V>
00218 {
00219
00220 TMPL static nat
00221 kernel (C* k, const C* m, nat rm, nat cm) {
00222
00223 ERROR ("kernel not available for matrix over any ring");
00224 }
00225
00226 };
00227
00228
00229
00230
00231
00232 template<typename V, typename W>
00233 struct implementation<matrix_image,V,matrix_ring_naive<W> >:
00234 public implementation<matrix_echelon,V>
00235 {
00236 typedef implementation<matrix_echelon,V> Mat;
00237
00238 TMPL static nat
00239 image (C* k, const C* m, nat rm, nat cm) {
00240
00241 ERROR ("image not available for matrix over any ring");
00242 }
00243
00244 TMPL static nat
00245 rank (const C* m, nat rm, nat cm) {
00246 VERIFY (rm > 0 && cm > 0, "unexpected empty matrix");
00247 nat i, len_c= aligned_size<C,V> (rm * cm);
00248 C* c= mmx_new<C> (len_c);
00249 Mat::copy (c, m, rm, cm);
00250 Mat::col_echelon (c, NULL, rm, cm);
00251 for (i=0; i<cm; i++)
00252 if (Mat::col_is_zero (c, i, rm, cm)) break;
00253 mmx_delete<C> (c, len_c);
00254 return i;
00255 }
00256
00257 };
00258
00259
00260
00261
00262
00263 template<typename V, typename W>
00264 struct implementation<matrix_invert,V,matrix_ring_naive<W> >:
00265 public implementation<matrix_echelon,V>
00266 {
00267 typedef implementation<matrix_determinant,V> Mat;
00268 typedef implementation<vector_linear,vector_naive> Vec;
00269
00270 TMPL static void
00271 invert (C* k, const C* s, nat n) {
00272 if (n == 0) return;
00273 nat l= default_aligned_size<C> (n + 1);
00274 C* d= mmx_new<C> (l);
00275 Mat::characteristic_polynomial (d, s, n);
00276
00277 C p= - mmx::invert (d[0]);
00278 nat ll= aligned_size<C,V> (n * n);
00279 C* aux= mmx_new<C> (ll);
00280 Vec::clear (aux, n * n);
00281 for (nat j= 0; j < n; j++)
00282 * (k + Mat::index (j, j, n, n))= d[n];
00283 for (nat i= n-1; i > 0; i--) {
00284 Mat::mul (aux, k, s, n, n, n);
00285 Mat::copy (k, aux, n, n);
00286 for (nat j= 0; j < n; j++)
00287 * (k + Mat::index (j, j, n, n)) += d[i];
00288 }
00289 Vec::mul (k, p, n * n);
00290 mmx_delete<C> (d, l);
00291 mmx_delete<C> (aux, ll);
00292 }
00293
00294 };
00295
00296 #undef TMPL
00297 }
00298 #endif //__MMX__MATRIX_RING_NAIVE__HPP