You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							321 lines
						
					
					
						
							11 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							321 lines
						
					
					
						
							11 KiB
						
					
					
				| /*=========================================================================== | |
|   | |
|  Copyright (C) 2007-2015 Yves Renard, Julien Pommier. | |
|   | |
|  This file is a part of GETFEM++ | |
|   | |
|  Getfem++  is  free software;  you  can  redistribute  it  and/or modify it | |
|  under  the  terms  of the  GNU  Lesser General Public License as published | |
|  by  the  Free Software Foundation;  either version 3 of the License,  or | |
|  (at your option) any later version along with the GCC Runtime Library | |
|  Exception either version 3.1 or (at your option) any later version. | |
|  This program  is  distributed  in  the  hope  that it will be useful,  but | |
|  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
|  or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public | |
|  License and GCC Runtime Library Exception for more details. | |
|  You  should  have received a copy of the GNU Lesser General Public License | |
|  along  with  this program;  if not, write to the Free Software Foundation, | |
|  Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA. | |
|   | |
| ===========================================================================*/ | |
| // RECTANGULAR_MATRIX_PARAM | |
| // SQUARED_MATRIX_PARAM | |
| // ENDPARAM; | |
|  | |
| #include "gmm/gmm_kernel.h" | |
| #include "gmm/gmm_dense_lu.h" | |
| #include "gmm/gmm_dense_qr.h" | |
| #include "gmm/gmm_condition_number.h" | |
|  | |
| using std::endl; using std::cout; using std::cerr; | |
| using std::ends; using std::cin; | |
| using gmm::size_type; | |
| bool print_debug = false; | |
| 
 | |
| // template <typename MAT, typename T> void print_for_matlab(const MAT &m, T) {  | |
| //   cout.precision(16); | |
| //   cout << "[ "; | |
| //   for (size_type i = 0; i < gmm::mat_nrows(m); ++i) { | |
| //     for (size_type j = 0; j < gmm::mat_ncols(m); ++j) cout << " " << m(i,j); | |
| //     if (i != gmm::mat_nrows(m)-1) cout << " ; \n"; | |
| //   } | |
| //   cout << " ]" << endl; | |
| // } | |
|  | |
| // template <typename MAT, typename T> void print_for_matlab(const MAT &m, | |
| // 						    std::complex<T>) {  | |
| //   cout.precision(16); | |
| //   cout << "[ "; | |
| //   for (size_type i = 0; i < gmm::mat_nrows(m); ++i) { | |
| //     for (size_type j = 0; j < gmm::mat_ncols(m); ++j) | |
| //       cout << " (" << m(i,j).real() << "+" << m(i,j).imag() << "*i)" ; | |
| //     if (i != gmm::mat_nrows(m)-1) cout << " ; \n"; | |
| //   } | |
| //   cout << " ]" << endl; | |
| // } | |
|  | |
| // template <typename MAT> inline void print_for_matlab(const MAT &m) | |
| // { print_for_matlab(m, gmm::linalg_traits<MAT>::value_type()); } | |
|  | |
| template <typename T> inline T real_or_complex(double a, double, T) | |
| { return T(a); } | |
| 
 | |
| template <typename T> inline | |
| std::complex<T> real_or_complex(double a, double b, std::complex<T>) { | |
|   typedef typename gmm::number_traits<T>::magnitude_type R; | |
|   return std::complex<T>(R(a), R(b));  | |
| } | |
| 
 | |
| template <typename T> struct cmp_eval { | |
|   bool operator()(T a, T b) { | |
|     typedef typename gmm::number_traits<T>::magnitude_type R; | |
|     // R prec = gmm::default_tol(R()); | |
|     R dr = gmm::real(a) - gmm::real(b); | |
|     R di = gmm::imag(a) - gmm::imag(b); | |
|     if (gmm::abs(dr) > gmm::abs(di)) return (dr<R(0)); else return (di<R(0)); | |
|   } | |
| }; | |
| 
 | |
| template <typename T> void sort_eval(std::vector<T> &v) { | |
|   std::sort(v.begin(), v.end(), cmp_eval<T>()); | |
| }  | |
| 
 | |
| 
 | |
| template <typename MAT1, typename MAT2> | |
| bool test_procedure(const MAT1 &m1_, const MAT2 &m2_) { | |
|   MAT1  &m1 = const_cast<MAT1  &>(m1_); | |
|   MAT2  &m2 = const_cast<MAT2  &>(m2_); | |
|   typedef typename gmm::linalg_traits<MAT1>::value_type T; | |
|   typedef typename gmm::number_traits<T>::magnitude_type R; | |
|   R prec = gmm::default_tol(R()); | |
|   R error; | |
|   static size_type nb_iter(0); | |
|   ++nb_iter; | |
| 
 | |
|   // gmm::qr_factor(A, Q, R) is tested in test_gmm_mult.C | |
|  | |
|   // | |
|   // test for gmm::qr_factor(A), apply_house_right and apply_house_left | |
|   // | |
|   size_type m = gmm::mat_nrows(m1), n = gmm::mat_ncols(m1); | |
|   size_type k = size_type(rand() % 50); | |
| 
 | |
|   if (print_debug) { | |
|     static int nexpe = 0; | |
|     cout << "Begin experiment " << ++nexpe << "\n\nwith " << m1 << "\n\n";  | |
|     gmm::set_warning_level(3); | |
|   } | |
|      | |
|   gmm::dense_matrix<T> dm1(m, n); | |
|   gmm::copy(m1, dm1); | |
|   if (m >= n) { | |
|     gmm::dense_matrix<T> q(k,m), qaux(k,m), q2(m,k), dm1aux(k,n), m1aux(k,n); | |
|     gmm::fill_random(q); gmm::copy(q, qaux); | |
|     gmm::mult(q, m1, m1aux); | |
| 
 | |
|     gmm::qr_factor(dm1); | |
|     gmm::copy(dm1, m1); | |
|      | |
|     gmm::apply_house_right(dm1, q); | |
|     for (size_type j = 0; j < n; ++j) | |
|       for (size_type i = j+1; i < m; ++i) | |
| 	dm1(i, j) = T(0); | |
|     gmm::mult(q, dm1, dm1aux); | |
|     gmm::add(gmm::scaled(m1aux, T(-1)), dm1aux); | |
|     error = gmm::mat_euclidean_norm(dm1aux); | |
|     if (!(error <= prec * R(10000)))  | |
|       GMM_ASSERT1(false, "Error too large: " << error); | |
| 
 | |
|     gmm::copy(gmm::identity_matrix(), q); | |
|     gmm::apply_house_right(m1, q); | |
|     size_type min_km = std::min(k, m); | |
|     gmm::dense_matrix<T> a(min_km, min_km), b(min_km, min_km); | |
|     gmm::copy(gmm::identity_matrix(), b); | |
|     if (k > m) gmm::mult(gmm::conjugated(q), q, a); | |
|     else gmm::mult(q, gmm::conjugated(q), a); | |
|     gmm::add(gmm::scaled(b, T(-1)), a); | |
|     error = gmm::mat_euclidean_norm(a); | |
|     if (!(error <= prec * R(10000))) | |
|       GMM_ASSERT1(false, "Error too large: " << error); | |
|        | |
|     gmm::copy(gmm::conjugated(qaux), q2); | |
|     gmm::apply_house_left(m1, q2); | |
|     gmm::mult(gmm::conjugated(q2), dm1, dm1aux); | |
|     gmm::add(gmm::scaled(m1aux, T(-1)), dm1aux); | |
|     error = gmm::mat_euclidean_norm(dm1aux); | |
|     if (!(error <= prec * R(10000))) | |
|       GMM_ASSERT1(false, "Error too large: " << error); | |
| 
 | |
|   } | |
|   else { | |
|     gmm::dense_matrix<T> q(k,n), qaux(k,n), q2(n,k), dm1aux(k,m), m1aux(k,m); | |
|     gmm::fill_random(q); gmm::copy(q, qaux); | |
|     gmm::mult(q, gmm::transposed(m1), m1aux); | |
| 
 | |
|     gmm::qr_factor(gmm::transposed(dm1)); | |
|     gmm::copy(dm1, m1); | |
|      | |
|     gmm::apply_house_right(gmm::transposed(dm1), q); | |
|     for (size_type i = 0; i < m; ++i) | |
|       for (size_type j = i+1; j < n; ++j) | |
| 	dm1(i, j) = T(0); | |
|     gmm::mult(q, gmm::transposed(dm1), dm1aux); | |
|     gmm::add(gmm::scaled(m1aux, T(-1)), dm1aux); | |
|     error = gmm::mat_euclidean_norm(dm1aux); | |
|     if (!(error <= prec * R(10000)))  | |
|       GMM_ASSERT1(false, "Error too large: " << error); | |
| 
 | |
|     gmm::copy(gmm::identity_matrix(), q); | |
|     gmm::apply_house_right(gmm::transposed(m1), q); | |
|     size_type min_km = std::min(k, n); | |
|     gmm::dense_matrix<T> a(min_km, min_km), b(min_km, min_km); | |
|     gmm::copy(gmm::identity_matrix(), b); | |
|     if (k > n) gmm::mult(gmm::conjugated(q), q, a); | |
|     else gmm::mult(q, gmm::conjugated(q), a); | |
|     gmm::add(gmm::scaled(b, T(-1)), a); | |
|     error = gmm::mat_euclidean_norm(a); | |
|     if (!(error <= prec * R(10000))) | |
|       GMM_ASSERT1(false, "Error too large: " << error); | |
|        | |
|     gmm::copy(gmm::conjugated(qaux), q2); | |
|     gmm::apply_house_left(gmm::transposed(m1), q2); | |
|     gmm::mult(gmm::conjugated(q2), gmm::transposed(dm1), dm1aux); | |
|     gmm::add(gmm::scaled(m1aux, T(-1)), dm1aux); | |
|     error = gmm::mat_euclidean_norm(dm1aux); | |
|     if (!(error <= prec * R(10000)))  | |
|       GMM_ASSERT1(false, "Error too large: " << error); | |
| 
 | |
|   } | |
|    | |
|   // | |
|   // Test for implicit_qr_algorithm | |
|   // | |
|  | |
|    | |
| 
 | |
|   m = gmm::mat_nrows(m2); | |
|   gmm::dense_matrix<T> cq(m, m), cr(m, m), ca(m, m);   | |
|   std::vector<T> cv(m); | |
|   std::vector<std::complex<R> > eigc(m), cvc(m); | |
| 
 | |
| 
 | |
|   gmm::fill_random(ca); | |
|   std::complex<R> det1(gmm::lu_det(ca)), det2(1); | |
|   implicit_qr_algorithm(ca, eigc, cq); | |
|   for (size_type i = 0; i < m; ++i) det2 *= eigc[i]; | |
|   if (gmm::abs(det1 - det2) > (gmm::abs(det1)+gmm::abs(det2))/R(100)) | |
|     GMM_ASSERT1(false, "Error in QR or det. det lu: " << det1 | |
| 	      << " det qr: " << det2); | |
|   if (print_debug) | |
|     cout << "det lu = " << det1 << "  det qr = " << det2 << endl; | |
| 
 | |
|   if (m > 0) do { | |
|     gmm::fill_random(cq); | |
|   } while (gmm::abs(gmm::lu_det(cq)) < sqrt(prec) | |
| 	   || gmm::condition_number(cq) > R(1000)); | |
|   gmm::copy(cq, cr); | |
|   gmm::lu_inverse(cr); | |
| 
 | |
|    | |
| 
 | |
|   gmm::fill_random(cv); | |
|   if (m >  0) cv[ 0] = real_or_complex(     0.0,  0.0, cv[0]); | |
|   if (m >  1) cv[ 1] = real_or_complex(     0.0,  0.0, cv[0]); | |
|   if (m >  2) cv[ 2] = real_or_complex(     0.01,-0.1, cv[0]); | |
|   if (m >  3) cv[ 3] = real_or_complex(     0.01, 0.1, cv[0]); | |
|   if (m >  4) cv[ 4] = real_or_complex(    -2.0,  3.0, cv[0]); | |
|   if (m >  5) cv[ 5] = real_or_complex(    -2.0,  3.0, cv[0]); | |
|   if (m >  6) cv[ 6] = real_or_complex(   -50.0,  3.0, cv[0]); | |
|   if (m >  7) cv[ 7] = real_or_complex(   100.0,  1.0, cv[0]); | |
|   if (m >  8) cv[ 8] = real_or_complex(   300.0,  1.0, cv[0]); | |
|   if (m >  9) cv[ 9] = real_or_complex(   500.0,  1.0, cv[0]); | |
|   if (m > 10) cv[10] = real_or_complex(  1000.0,  1.0, cv[0]); | |
|   if (m > 11) cv[11] = real_or_complex(  4000.0,  1.0, cv[0]); | |
|   if (m > 12) cv[12] = real_or_complex(  5000.0,  1.0, cv[0]); | |
|   if (m > 13) cv[13] = real_or_complex( 10000.0,  1.0, cv[0]); | |
|   if (m > 14) cv[14] = real_or_complex( 80000.0,  1.0, cv[0]); | |
|   if (m > 15) cv[15] = real_or_complex(100000.0,  1.0, cv[0]); | |
|   gmm::clear(m2); | |
|   for (size_type l = 0; l < m; ++l) m2(l, l) = cv[l]; | |
|   gmm::mult(cq, m2, ca);  | |
|   gmm::mult(ca, cr, ca); | |
|    | |
|   implicit_qr_algorithm(ca, eigc, cq); | |
|   gmm::copy(cv, cvc); | |
|    | |
|   sort_eval(cvc); | |
|   sort_eval(eigc); | |
|   error = gmm::vect_dist2(cvc, eigc); | |
|   if (!(error <= sqrt(prec) * gmm::vect_norm2(cv) * R(10))) | |
|     GMM_ASSERT1(false, "Error in QR algorithm, error = " << error); | |
| 
 | |
|   gmm::dense_matrix<T> aa(m, m), bb(m, m); | |
|   gmm::mult(gmm::conjugated(cq), ca, aa); | |
|   gmm::mult(aa, cq, bb); | |
|   for (size_type i = 0; i < m; ++i) | |
|     for (size_type j = (i == 0) ? 0 : i-1; j < m; ++j) | |
|       bb(i, j) = T(0); | |
|   error = gmm::mat_maxnorm(bb); | |
|   if (!(error <= sqrt(prec) * gmm::vect_norm2(cv) * R(10))) | |
|     GMM_ASSERT1(false, "Error in Schur vectors, error = "<< error);  | |
| 
 | |
|   // | |
|   // Test for symmetric_qr_algorithm | |
|   // | |
|  | |
|   m = gmm::mat_nrows(m2); | |
|   std::vector<R> cvr(m), eigcr(m); | |
|   if (m > 0) do { | |
|     gmm::fill_random(cr); | |
|   } while (gmm::abs(gmm::lu_det(cr)) < sqrt(prec) | |
| 	   || gmm::condition_number(cr) > R(1000)); | |
|    | |
|   gmm::qr_factor(cr, cq, ca); | |
|   gmm::fill_random(cvr); | |
| 
 | |
|   gmm::copy(gmm::identity_matrix(), m2); | |
| 
 | |
|   if (m >  0) cvr[ 0] = R(     0.0 ); | |
|   if (m >  1) cvr[ 1] = R(     0.0 ); | |
|   if (m >  2) cvr[ 2] = R(     0.01); | |
|   if (m >  3) cvr[ 3] = R(     0.01); | |
|   if (m >  4) cvr[ 4] = R(    -2.0 ); | |
|   if (m >  5) cvr[ 5] = R(    -2.0 ); | |
|   if (m >  6) cvr[ 6] = R(   -50.0 ); | |
|   if (m >  7) cvr[ 7] = R(   100.0 ); | |
|   if (m >  8) cvr[ 8] = R(   300.0 ); | |
|   if (m >  9) cvr[ 9] = R(   500.0 ); | |
|   if (m > 10) cvr[10] = R(  1000.0 ); | |
|   if (m > 11) cvr[11] = R(  4000.0 ); | |
|   if (m > 12) cvr[12] = R(  5000.0 ); | |
|   if (m > 13) cvr[13] = R( 10000.0 ); | |
|   if (m > 14) cvr[14] = R( 80000.0 ); | |
|   if (m > 15) cvr[15] = R(100000.0 ); | |
|   gmm::clear(m2); | |
|   for (size_type l = 0; l < m; ++l) m2(l, l) = cvr[l]; | |
| 
 | |
|   gmm::mult(gmm::conjugated(cq), m2, ca);  | |
|   gmm::mult(ca, cq, ca); | |
|    | |
|   symmetric_qr_algorithm(ca, eigcr, cq); | |
| 
 | |
|   for (size_type l = 0; l < m; ++l) { | |
|      std::vector<T> vy(m); | |
|      gmm::mult(ca, gmm::mat_col(cq, l), | |
| 	       gmm::scaled(gmm::mat_col(cq, l), -eigcr[l]), vy); | |
|      error = gmm::vect_norm2(vy); | |
|      if (!(error <= sqrt(prec) * gmm::vect_norm2(cvr) * R(10)))  | |
|        GMM_ASSERT1(false, "Error too large: " << error); | |
| 
 | |
|   } | |
| 
 | |
|   sort_eval(cvr); | |
|   sort_eval(eigcr); | |
|   error = gmm::vect_dist2(cvr, eigcr); | |
|   if (!(error <= sqrt(prec) * gmm::vect_norm2(cvr) * R(10))) | |
|     GMM_ASSERT1(false, "Error in QR algorithm."); | |
| 
 | |
|   if (nb_iter == 100) return true; | |
|   return false; | |
| 
 | |
| }
 |