algebramix_doc 0.3
/Users/mourrain/Devel/mmx/algebramix/include/algebramix/matrix_ring_naive.hpp
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines