algebramix_doc 0.3
|
00001 00002 /****************************************************************************** 00003 * MODULE : matrix_ring_naive.hpp 00004 * DESCRIPTION: Naive matrix operations over any ring 00005 * COPYRIGHT : (C) 2007 G. Lecerf 00006 ******************************************************************************* 00007 * This software falls under the GNU general public license and comes WITHOUT 00008 * ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details. 00009 * If you don't have this file, write to the Free Software Foundation, Inc., 00010 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 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 * Naive matrices over any ring 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 * Echelon forms 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 // Perform column pivoting from (ri, ci) to (rf, cf). 00067 // Comments are the same as in matrix_naive 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 // search pivot 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 // put pivot on the left 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 // column reduction 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 // call the pivoting on the non triangular sub-matrix 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 }; // implementation<matrix_echelon,V,matrix_ring_naive<W> > 00135 00136 /****************************************************************************** 00137 * Determinant and characteristic polynomial with no division 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 00150 static inline void 00151 berkowitz (C* d, const C* s, nat n) { 00152 // x^n + d[n-1] x^[n-1] + ... + d[0] is the characteristic 00153 // polynomial of s. 00154 // d must have allocated size at least n + 1, and we set d[n]=1 00155 // This is an implementation of Berkowitz' algorithm (1984). 00156 if (n == 0) { d[0]= 1; return; } // FIXME: please check correctness 00157 d[0]= - *(s + Mat::index (0, 0, n, n)); d[1]= 1; 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 // Apply Samuelson's formula to deduce charpoly (s[0..i, 0..i]) 00170 // from charpoly (s[0..i-1, 0..i-1]). 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 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]; // namely -1 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 r= (n & 1) ? - d[0] : d[0]; 00199 mmx_delete<C> (d, l); 00200 } 00201 00202 TMPL static inline C 00203 characteristic_polynomial (C* d, const C* s, nat n) { 00204 berkowitz (d, s, n); 00205 } 00206 00207 }; // implementation<matrix_determinant,matrix_ring_naive<W> > 00208 00209 /****************************************************************************** 00210 * Kernel 00211 ******************************************************************************/ 00212 00213 template<typename V, typename W> 00214 struct implementation<matrix_kernel,V,matrix_ring_naive<W> >: 00215 public implementation<matrix_echelon,V> 00216 { 00217 00218 TMPL static nat 00219 kernel (C* k, const C* m, nat rm, nat cm) { 00220 // return the dimension of the kernel 00221 ERROR ("kernel not available for matrix over any ring"); 00222 } 00223 00224 }; // implementation<matrix_kernel,V,matrix_ring_naive<W> > 00225 00226 /****************************************************************************** 00227 * Image and rank 00228 ******************************************************************************/ 00229 00230 template<typename V, typename W> 00231 struct implementation<matrix_image,V,matrix_ring_naive<W> >: 00232 public implementation<matrix_echelon,V> 00233 { 00234 typedef implementation<matrix_echelon,V> Mat; 00235 00236 TMPL static nat 00237 image (C* k, const C* m, nat rm, nat cm) { 00238 // return the dimension of the image 00239 ERROR ("image not available for matrix over any ring"); 00240 } 00241 00242 TMPL static nat 00243 rank (const C* m, nat rm, nat cm) { 00244 VERIFY (rm > 0 && cm > 0, "unexpected empty matrix"); 00245 nat i, len_c= aligned_size<C,V> (rm * cm); 00246 C* c= mmx_new<C> (len_c); 00247 Mat::copy (c, m, rm, cm); 00248 Mat::col_echelon (c, NULL, rm, cm); 00249 for (i=0; i<cm; i++) 00250 if (Mat::col_is_zero (c, i, rm, cm)) break; 00251 mmx_delete<C> (c, len_c); 00252 return i; 00253 } 00254 00255 }; // implementation<matrix_image,V,matrix_ring_naive<W> > 00256 00257 /****************************************************************************** 00258 * Inversion 00259 ******************************************************************************/ 00260 00261 template<typename V, typename W> 00262 struct implementation<matrix_invert,V,matrix_ring_naive<W> >: 00263 public implementation<matrix_echelon,V> 00264 { 00265 00266 TMPL static void 00267 invert (C* k, const C* m, nat n) { 00268 ERROR ("invert not available for matrix over any ring"); 00269 } 00270 00271 }; // implementation<matrix_invert,V,matrix_ring_naive<W> > 00272 00273 #undef TMPL 00274 }//namespace mmx 00275 #endif //__MMX__MATRIX_RING_NAIVE__HPP