Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members

plapack.cc

Go to the documentation of this file.
00001 // -*- C++ -*- 00002 00003 // PLearn (A C++ Machine Learning Library) 00004 // Copyright (C) 1998 Pascal Vincent 00005 // Copyright (C) 1999-2002 Pascal Vincent, Yoshua Bengio, Rejean Ducharme and University of Montreal 00006 // 00007 00008 // Redistribution and use in source and binary forms, with or without 00009 // modification, are permitted provided that the following conditions are met: 00010 // 00011 // 1. Redistributions of source code must retain the above copyright 00012 // notice, this list of conditions and the following disclaimer. 00013 // 00014 // 2. Redistributions in binary form must reproduce the above copyright 00015 // notice, this list of conditions and the following disclaimer in the 00016 // documentation and/or other materials provided with the distribution. 00017 // 00018 // 3. The name of the authors may not be used to endorse or promote 00019 // products derived from this software without specific prior written 00020 // permission. 00021 // 00022 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 00023 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00024 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 00025 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00026 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 00027 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00028 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00029 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00030 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00031 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00032 // 00033 // This file is part of the PLearn library. For more information on the PLearn 00034 // library, go to the PLearn Web site at www.plearn.org 00035 00036 /* ******************************************************* 00037 * $Id: plapack.cc,v 1.10 2004/06/29 13:22:05 tihocan Exp $ 00038 * This file is part of the PLearn library. 00039 ******************************************************* */ 00040 00041 #include <cstdlib> 00042 #include "plapack.h" 00043 #include <algorithm> 00044 #include "random.h" 00045 00046 namespace PLearn { 00047 using namespace std; 00048 00049 int eigen_SymmMat(Mat& in, Vec& e_value, Mat& e_vector, int& n_evalues_found, 00050 bool compute_all, int nb_eigen, bool compute_vectors, bool largest_evalues) 00051 { 00052 PLWARNING("eigen_SymmMat is deprecated: use eigenVecOfSymmMat or lapackEIGEN instead"); 00053 00054 #ifndef USE_BLAS_SPECIALISATIONS 00055 PLERROR("eigen_SymmMat: LAPACK not available on this system!"); 00056 return 0; 00057 #else 00058 if (!in.isSymmetric()) 00059 PLERROR("eigen_SymmMat: Your input matrix is not symmetric\n"); 00060 00061 // some check 00062 if (nb_eigen < 1 || nb_eigen > in.length()) 00063 PLERROR("The number of desired eigenvalues (%d) must be in range [1,%d]", nb_eigen, in.length()); 00064 00065 if (compute_all) 00066 { 00067 if (e_vector.length() != in.length() || e_vector.width() != in.width()) 00068 e_vector.resize(in.length(), in.width()); 00069 if (in.length() != e_value.length()) 00070 e_value.resize(in.length()); 00071 } 00072 else 00073 { 00074 if (e_vector.length() != nb_eigen || e_vector.width() != in.width()) 00075 e_vector.resize(nb_eigen, in.width()); 00076 if (nb_eigen != e_value.length()) 00077 e_value.resize(nb_eigen); 00078 } 00079 00080 // for the moment, we do not accept sub-matrices... 00081 if (in.mod() != in.width()) 00082 PLERROR("The input matrix cannot be a sub-matrix..."); 00083 00084 // we set the parameters to call the LAPACK Fortran function 00085 // if compute_all==true, we call <ssyev> 00086 // if compute_all==false, we call <ssyevx> 00087 00088 int INFO = 1; 00089 if (compute_all) 00090 { 00091 char* JOBZ; 00092 if (compute_vectors) 00093 JOBZ = "V"; 00094 else 00095 JOBZ = "N"; 00096 char* UPLO = "U"; 00097 int N = in.length(); 00098 real* A = in.data(); 00099 int LDA = N; 00100 real* W = new real[N]; 00101 int LWORK = 3*N; 00102 real* WORK = new real[LWORK]; 00103 00104 // we now call the LAPACK Fortran function <ssyev> 00105 #ifdef USEFLOAT 00106 ssyev_(JOBZ, UPLO, &N, A, &LDA, W, WORK, &LWORK, &INFO); 00107 #endif 00108 #ifdef USEDOUBLE 00109 dsyev_(JOBZ, UPLO, &N, A, &LDA, W, WORK, &LWORK, &INFO); 00110 #endif 00111 00112 if (INFO != 0) 00113 { 00114 PLWARNING("eigen_SymmMat: something in ssyev got wrong. Error code %d",INFO); 00115 n_evalues_found = 0; 00116 } 00117 else 00118 { 00119 n_evalues_found = N; 00120 for (int i=0; i<N; i++) 00121 e_value[i] = W[i]; 00122 00123 if (compute_vectors) 00124 { 00125 real* p_evector = e_vector.data(); 00126 real* p_a = A; 00127 for (int i=0; i<N; i++) 00128 for (int j=0; j<N; j++, p_evector++, p_a++) 00129 *p_evector = *p_a; 00130 } 00131 } 00132 delete[] W; 00133 delete[] WORK; 00134 } 00135 else 00136 { 00137 char* JOBZ; 00138 if (compute_vectors) 00139 JOBZ = "V"; 00140 else 00141 JOBZ = "N"; 00142 char* RANGE = "I"; 00143 char* UPLO = "U"; 00144 int N = in.length(); 00145 real* A = in.data(); 00146 int LDA = N; 00147 real VL, VU; // not referenced 00148 int IL,IU; 00149 if (largest_evalues) 00150 { 00151 IL = N - nb_eigen + 1; 00152 IU = N; 00153 } 00154 else 00155 { 00156 IL = 1; 00157 IU = nb_eigen; 00158 } 00159 real ABSTOL = 1e-10; 00160 int M; 00161 real* W= new real[N]; 00162 int LDZ = N; 00163 real* Z = new real[LDZ*nb_eigen]; 00164 int LWORK = 8*N; 00165 real* WORK = new real[LWORK]; 00166 int* IWORK = new int[5*N]; 00167 int* IFAIL = new int[N]; 00168 00169 // we now call the LAPACK Fortran function <ssyevx> 00170 lapack_Xsyevx_(JOBZ, RANGE, UPLO, &N, A, &LDA, &VL, &VU, &IL, &IU, &ABSTOL, &M, W, Z, &LDZ, WORK, &LWORK, IWORK, IFAIL, &INFO); 00171 00172 n_evalues_found = M; 00173 if (M != nb_eigen) 00174 cout << "eigen_SymmMat: something in ssyevx got wrong." << endl 00175 << "The number of eigenvalues found (" << M 00176 << ") is different from what we asked (" << nb_eigen << ")." << endl; 00177 00178 if (INFO != 0) 00179 { 00180 // cout << "eigen_SymmMat: something in ssyevx got wrong. Error code " 00181 // << INFO << endl << "See the man page of ssyevx for more details" 00182 // << endl; 00183 } 00184 else 00185 { 00186 for (int i=0; i<M; i++) 00187 e_value[i] = W[i]; 00188 00189 if (compute_vectors) 00190 { 00191 real* p_evector = e_vector.data(); 00192 real* p_z = Z; 00193 for (int i=0; i<M; i++) 00194 for (int j=0; j<N; j++, p_evector++, p_z++) 00195 *p_evector = *p_z; 00196 } 00197 } 00198 delete[] W; 00199 delete[] WORK; 00200 delete[] IWORK; 00201 delete[] IFAIL; 00202 } 00203 return INFO; 00204 #endif 00205 } 00206 00207 int eigen_SymmMat_decreasing(Mat& in, Vec& e_value, Mat& e_vector, int& n_evalues_found, 00208 bool compute_all, int nb_eigen, bool compute_vectors, bool largest_evalues) 00209 { 00210 PLWARNING("eigen_SymmMat_decreasing is deprecated: use eigenVecOfSymmMat or lapackEIGEN instead"); 00211 00212 int res = eigen_SymmMat(in, e_value, e_vector, n_evalues_found, 00213 compute_all, nb_eigen, compute_vectors, largest_evalues); 00214 e_value.swap(); 00215 e_vector.swapUpsideDown(); 00216 return res; 00217 } 00218 00219 int matInvert(Mat& in, Mat& inverse) 00220 { 00221 #ifndef USE_BLAS_SPECIALISATIONS 00222 PLERROR("eigen_SymmMat: LAPACK not available on this system!"); 00223 return 0; 00224 #else 00225 // PLWARNING("matInvert: Your input matrix will be over-written!"); 00226 00227 // some check 00228 if (in.length() != in.width()) 00229 PLERROR("The input matrix [%dx%d] must be square!", in.length(), in.width()); 00230 // for the moment, we do not accept sub-matrices... 00231 if (in.mod() != in.width()) 00232 PLERROR("The input matrix cannot be a sub-matrix..."); 00233 00234 int M = in.length(); 00235 int N = in.length(); 00236 real* A = in.data(); 00237 int LDA = N; 00238 int* IPIV = new int[N]; 00239 int INFO; 00240 00241 #ifdef USEFLOAT 00242 sgetrf_(&M, &N, A, &LDA, IPIV, &INFO); 00243 #endif 00244 #ifdef USEDOUBLE 00245 dgetrf_(&M, &N, A, &LDA, IPIV, &INFO); 00246 #endif 00247 00248 if (INFO != 0) 00249 { 00250 cout << "In matInvert: Error doing the inversion." << endl 00251 << "Check the man page of <sgetrf> with error code " << INFO 00252 << " for more details." << endl; 00253 00254 delete[] IPIV; 00255 return INFO; 00256 } 00257 00258 int LWORK = N; 00259 real* WORK = new real[LWORK]; 00260 00261 #ifdef USEFLOAT 00262 sgetri_(&N, A, &LDA, IPIV, WORK, &LWORK, &INFO); 00263 #endif 00264 #ifdef USEDOUBLE 00265 dgetri_(&N, A, &LDA, IPIV, WORK, &LWORK, &INFO); 00266 #endif 00267 00268 if (INFO != 0) 00269 { 00270 cout << "In matInvert: Error doing the inversion." << endl 00271 << "Check the man page of <sgetri> with error code " << INFO 00272 << " for more details." << endl; 00273 00274 delete[] IPIV; 00275 delete[] WORK; 00276 return INFO; 00277 } 00278 00279 delete[] IPIV; 00280 delete[] WORK; 00281 00282 real* p_inverse = inverse.data(); 00283 real* p_A = A; 00284 for (int i=0; i<N; i++) 00285 for (int j=0; j<M; j++, p_inverse++, p_A++) 00286 *p_inverse = *p_A; 00287 00288 return INFO; 00289 #endif 00290 } 00291 00292 00293 int lapackSolveLinearSystem(Mat& At, Mat& Bt, TVec<int>& pivots) 00294 { 00295 #ifdef BOUNDCHECK 00296 if(At.width() != Bt.width()) 00297 PLERROR("In lapackSolveLinearSystem: Incompatible dimensions"); 00298 #endif 00299 00300 int INFO; 00301 #ifndef USE_BLAS_SPECIALISATIONS 00302 PLERROR("lapackSolveLinearSystem: can't be called unless PLearn linked with LAPACK"); 00303 #else 00304 int N = At.width(); 00305 int NRHS = Bt.length(); 00306 real* Aptr = At.data(); 00307 int LDA = At.mod(); 00308 if(pivots.length()!=N) 00309 pivots.resize(N); 00310 int* IPIVptr = pivots.data(); 00311 real* Bptr = Bt.data(); 00312 int LDB = Bt.mod(); 00313 #ifdef USEFLOAT 00314 sgesv_(&N, &NRHS, Aptr, &LDA, IPIVptr, Bptr, &LDB, &INFO); 00315 #endif 00316 #ifdef USEDOUBLE 00317 dgesv_(&N, &NRHS, Aptr, &LDA, IPIVptr, Bptr, &LDB, &INFO); 00318 #endif 00319 #endif 00320 return INFO; 00321 } 00322 00323 // for matrices A such that A.length() <= A.width(), 00324 // find X s.t. A X = Y 00325 void solveLinearSystem(const Mat& A, const Mat& Y, Mat& X) 00326 { 00327 PLERROR("solveLinearSystem: not implemented yet"); 00328 } 00329 00330 // for matrices A such that A.length() >= A.width(), 00331 // find X s.t. X A = Y 00332 void solveTransposeLinearSystem(const Mat& A, const Mat& Y, Mat& X) 00333 { 00334 PLERROR("solveTransposeLinearSystem: not implemented yet"); 00335 } 00336 00337 Mat solveLinearSystem(const Mat& A, const Mat& B) 00338 { 00339 Mat Bt = transpose(B); 00340 Mat At = transpose(A); 00341 TVec<int> pivots(A.length()); 00342 int status = lapackSolveLinearSystem(At,Bt,pivots); 00343 if(status<0) 00344 PLERROR("Illegal value in argument of lapackSolveLinearSystem"); 00345 else if(status>0) 00346 PLERROR("In solveLinearSystem: The factorization has been completed, but the factor U is exactly singular, so the solution could not be computed."); 00347 return transpose(Bt); // return X 00348 } 00349 00350 Vec solveLinearSystem(const Mat& A, const Vec& b) 00351 { return solveLinearSystem(A,b.toMat(b.length(),1)).toVec(); } 00352 00353 00354 /* 00355 real hyperplane_distance(Vec x, Mat points) 00356 { 00357 if(x.length()!=points.width()) 00358 PLERROR("In hyperplane_distance, incompatible dimensions"); 00359 Vec ref = points(0); 00360 Mat tangentvecs = points.subMatRows(1,points.length()-1).copy(); 00361 tangentvecs -= ref; 00362 Mat A = productTranspose(tangentvecs,tangentvecs); 00363 Vec b = product(tangentvecs,x-ref); 00364 Vec alpha(tangentvecs.length()); 00365 Mat alphamat(alpha.length(),1,alpha); 00366 solveLinearSystemByCholesky(A,Mat(b.length(),1,b),alphamat); 00367 return norm(ref + transposeProduct(tangentvecs,alpha) - x); 00368 } 00369 */ 00370 00371 // Returns w that minimizes ||X.w - Y||^2 + lambda.||w||^2 00372 // under constraint \sum w_i = 1 00373 // Xt is the transposed of the input matrix X; Y is the target vector. 00374 // This doesn't include any bias term. 00375 Vec constrainedLinearRegression(const Mat& Xt, const Vec& Y, real lambda) 00376 { 00377 if(Y.length()!=Xt.width()) 00378 PLERROR("In hyperplane_distance, incompatible dimensions"); 00379 00380 int n = Xt.length(); 00381 Mat A(n+1,n+1); 00382 Vec b(n+1); 00383 00384 for(int i=0; i<n; i++) 00385 { 00386 A(n,i) = 0.5; 00387 A(i,n) = 0.5; 00388 b[i] = dot(Y,Xt(i)); 00389 for(int j=0; j<n; j++) 00390 { 00391 real dotprod = dot(Xt(i),Xt(j)); 00392 if(i!=j) 00393 A(i,j) = dotprod; 00394 else 00395 A(i,j) = dotprod + lambda; 00396 } 00397 } 00398 A(n,n) = 0.; 00399 b[n] = 0.5; 00400 00401 // cerr << "A = " << A << endl; 00402 // cerr << "b = " << b << endl; 00403 // cerr << "b\\A = " << solveLinearSystem(A,b) << endl; 00404 00405 Vec w_and_l = solveLinearSystem(A,b); 00406 return w_and_l.subVec(0,n); // return w 00407 } 00408 00409 00410 00411 Mat multivariate_normal(const Vec& mu, const Mat& A, int N) 00412 { 00413 Vec e_values; 00414 Mat e_vectors; 00415 Mat A_copy = A.copy(); 00416 int nb_evalues_found; 00417 eigen_SymmMat(A_copy, e_values, e_vectors, nb_evalues_found, true, mu.length(), true); 00418 Mat samples(0,mu.length()); 00419 for (int i = 0; i < N; i++) 00420 samples.appendRow(multivariate_normal(mu, e_values, e_vectors)); 00421 return samples; 00422 } 00423 00424 Vec multivariate_normal(const Vec& mu, const Mat& A) 00425 { 00426 return multivariate_normal(mu, A, 1).toVec(); 00427 } 00428 00429 Vec multivariate_normal(const Vec& mu, const Vec& e_values, const Mat& e_vectors) 00430 { 00431 int n = mu.length(); // the number of dimension 00432 Vec z(n), x(n); 00433 for (int i = 0; i < n; i++) 00434 z[i] = gaussian_01(); 00435 for (int i = 0; i < n; i++) 00436 { 00437 for (int j = 0; j < n; j++) 00438 x[i] += e_vectors[j][i] * sqrt(e_values[j]) * z[j]; 00439 x[i] += mu[i]; 00440 } 00441 return x; 00442 } 00443 00444 void multivariate_normal(Vec& x, const Vec& mu, const Vec& e_values, const Mat& e_vectors, Vec& z) 00445 { 00446 int n = mu.length(); // the number of dimension 00447 z.resize(n); 00448 x.resize(n); 00449 x.clear(); 00450 for (int i = 0; i < n; i++) 00451 z[i] = gaussian_01(); 00452 for (int i = 0; i < n; i++) 00453 { 00454 for (int j = 0; j < n; j++) 00455 x[i] += e_vectors[j][i] * sqrt(e_values[j]) * z[j]; 00456 x[i] += mu[i]; 00457 } 00458 } 00459 00460 void affineNormalization(Mat data, Mat W, Vec bias, real regularizer) 00461 { 00462 int d=data.width(); 00463 Vec& mu = bias; 00464 Mat covar(d,d); 00465 computeMeanAndCovar(data,mu,covar); 00466 Vec evalues(d); 00467 if (regularizer!=0) 00468 for (int i=0;i<d;i++) 00469 covar(i,i) += regularizer; 00470 int nev=0; 00471 eigen_SymmMat(covar,evalues,W,nev,true,d,true,true); 00472 for (int i=0;i<d;i++) 00473 W(i) *= real(1.0 / sqrt(evalues[i])); 00474 mu *= - real(1.0); // bias = -mu 00475 } 00476 00477 00478 } // end of namespace PLearn

Generated on Tue Aug 17 16:01:25 2004 for PLearn by doxygen 1.3.7