SNAP Library, Developer Reference  2012-10-15 15:06:59
SNAP, a general purpose network analysis and graph mining library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
linalg.cpp
Go to the documentation of this file.
00001 
00002 // Sparse-Column-Matrix
00003 void TSparseColMatrix::PMultiply(const TFltVV& B, int ColId, TFltV& Result) const {
00004     Assert(B.GetRows() >= ColN && Result.Len() >= RowN);
00005     int i, j; TFlt *ResV = Result.BegI();
00006     for (i = 0; i < RowN; i++) ResV[i] = 0.0;
00007     for (j = 0; j < ColN; j++) {
00008         const TIntFltKdV& ColV = ColSpVV[j]; int len = ColV.Len();
00009         for (i = 0; i < len; i++) {
00010             ResV[ColV[i].Key] += ColV[i].Dat * B(j,ColId);
00011         }
00012     }
00013 }
00014 
00015 void TSparseColMatrix::PMultiply(const TFltV& Vec, TFltV& Result) const {
00016     Assert(Vec.Len() >= ColN && Result.Len() >= RowN);
00017     int i, j; TFlt *ResV = Result.BegI();
00018     for (i = 0; i < RowN; i++) ResV[i] = 0.0;
00019     for (j = 0; j < ColN; j++) {
00020         const TIntFltKdV& ColV = ColSpVV[j]; int len = ColV.Len();
00021         for (i = 0; i < len; i++) {
00022             ResV[ColV[i].Key] += ColV[i].Dat * Vec[j];
00023         }
00024     }
00025 }
00026 
00027 void TSparseColMatrix::PMultiplyT(const TFltVV& B, int ColId, TFltV& Result) const {
00028     Assert(B.GetRows() >= RowN && Result.Len() >= ColN);
00029     int i, j, len; TFlt *ResV = Result.BegI();
00030     for (j = 0; j < ColN; j++) {
00031         const TIntFltKdV& ColV = ColSpVV[j];
00032         len = ColV.Len(); ResV[j] = 0.0;
00033         for (i = 0; i < len; i++) {
00034             ResV[j] += ColV[i].Dat * B(ColV[i].Key, ColId);
00035         }
00036     }
00037 }
00038 
00039 void TSparseColMatrix::PMultiplyT(const TFltV& Vec, TFltV& Result) const {
00040     Assert(Vec.Len() >= RowN && Result.Len() >= ColN);
00041     int i, j, len; TFlt *VecV = Vec.BegI(), *ResV = Result.BegI();
00042     for (j = 0; j < ColN; j++) {
00043         const TIntFltKdV& ColV = ColSpVV[j];
00044         len = ColV.Len(); ResV[j] = 0.0;
00045         for (i = 0; i < len; i++) {
00046             ResV[j] += ColV[i].Dat * VecV[ColV[i].Key];
00047         }
00048     }
00049 }
00050 
00052 // Sparse-Row-Matrix
00053 TSparseRowMatrix::TSparseRowMatrix(const TStr& MatlabMatrixFNm) {
00054    FILE *F = fopen(MatlabMatrixFNm.CStr(), "rt");  IAssert(F != NULL);
00055    TVec<TTriple<TInt, TInt, TSFlt> > MtxV;
00056    RowN = 0;  ColN = 0;
00057    while (! feof(F)) {
00058      int row=-1, col=-1; float val;
00059      if (fscanf(F, "%d %d %f\n", &row, &col, &val) == 3) {
00060        IAssert(row > 0 && col > 0);
00061        MtxV.Add(TTriple<TInt, TInt, TSFlt>(row, col, val));
00062        RowN = TMath::Mx(RowN, row);
00063        ColN = TMath::Mx(ColN, col);
00064      }
00065    }
00066    fclose(F);
00067    // create matrix
00068    MtxV.Sort();
00069    RowSpVV.Gen(RowN);
00070    int cnt = 0;
00071    for (int row = 1; row <= RowN; row++) {
00072      while (cnt < MtxV.Len() && MtxV[cnt].Val1 == row) {
00073        RowSpVV[row-1].Add(TIntFltKd(MtxV[cnt].Val2-1, MtxV[cnt].Val3()));
00074        cnt++;
00075      }
00076    }
00077 }
00078 
00079 void TSparseRowMatrix::PMultiplyT(const TFltVV& B, int ColId, TFltV& Result) const {
00080     Assert(B.GetRows() >= RowN && Result.Len() >= ColN);
00081     for (int i = 0; i < ColN; i++) Result[i] = 0.0;
00082     for (int j = 0; j < RowN; j++) {
00083         const TIntFltKdV& RowV = RowSpVV[j]; int len = RowV.Len();
00084         for (int i = 0; i < len; i++) {
00085             Result[RowV[i].Key] += RowV[i].Dat * B(j,ColId);
00086         }
00087     }
00088 }
00089 
00090 void TSparseRowMatrix::PMultiplyT(const TFltV& Vec, TFltV& Result) const {
00091     Assert(Vec.Len() >= RowN && Result.Len() >= ColN);
00092     for (int i = 0; i < ColN; i++) Result[i] = 0.0;
00093     for (int j = 0; j < RowN; j++) {
00094         const TIntFltKdV& RowV = RowSpVV[j]; int len = RowV.Len();
00095         for (int i = 0; i < len; i++) {
00096             Result[RowV[i].Key] += RowV[i].Dat * Vec[j];
00097         }
00098     }
00099 }
00100 
00101 void TSparseRowMatrix::PMultiply(const TFltVV& B, int ColId, TFltV& Result) const {
00102     Assert(B.GetRows() >= ColN && Result.Len() >= RowN);
00103     for (int j = 0; j < RowN; j++) {
00104         const TIntFltKdV& RowV = RowSpVV[j];
00105         int len = RowV.Len(); Result[j] = 0.0;
00106         for (int i = 0; i < len; i++) {
00107             Result[j] += RowV[i].Dat * B(RowV[i].Key, ColId);
00108         }
00109     }
00110 }
00111 
00112 void TSparseRowMatrix::PMultiply(const TFltV& Vec, TFltV& Result) const {
00113     Assert(Vec.Len() >= ColN && Result.Len() >= RowN);
00114     for (int j = 0; j < RowN; j++) {
00115         const TIntFltKdV& RowV = RowSpVV[j];
00116         int len = RowV.Len(); Result[j] = 0.0;
00117         for (int i = 0; i < len; i++) {
00118             Result[j] += RowV[i].Dat * Vec[RowV[i].Key];
00119         }
00120     }
00121 }
00122 
00124 // Full-Col-Matrix
00125 TFullColMatrix::TFullColMatrix(const TStr& MatlabMatrixFNm): TMatrix() {
00126     TLAMisc::LoadMatlabTFltVV(MatlabMatrixFNm, ColV);
00127     RowN=ColV[0].Len(); ColN=ColV.Len();
00128     for (int i = 0; i < ColN; i++) {
00129         IAssertR(ColV[i].Len() == RowN, TStr::Fmt("%d != %d", ColV[i].Len(), RowN));
00130     }
00131 }
00132 
00133 void TFullColMatrix::PMultiplyT(const TFltVV& B, int ColId, TFltV& Result) const {
00134     Assert(B.GetRows() >= RowN && Result.Len() >= ColN);
00135     for (int i = 0; i < ColN; i++) {
00136         Result[i] = TLinAlg::DotProduct(B, ColId, ColV[i]);
00137     }
00138 }
00139 
00140 void TFullColMatrix::PMultiplyT(const TFltV& Vec, TFltV& Result) const {
00141     Assert(Vec.Len() >= RowN && Result.Len() >= ColN);
00142     for (int i = 0; i < ColN; i++) {
00143         Result[i] = TLinAlg::DotProduct(Vec, ColV[i]);
00144     }
00145 }
00146 
00147 void TFullColMatrix::PMultiply(const TFltVV& B, int ColId, TFltV& Result) const {
00148     Assert(B.GetRows() >= ColN && Result.Len() >= RowN);
00149     for (int i = 0; i < RowN; i++) { Result[i] = 0.0; }
00150     for (int i = 0; i < ColN; i++) {
00151         TLinAlg::AddVec(B(i, ColId), ColV[i], Result, Result);
00152     }
00153 }
00154 
00155 void TFullColMatrix::PMultiply(const TFltV& Vec, TFltV& Result) const {
00156     Assert(Vec.Len() >= ColN && Result.Len() >= RowN);
00157     for (int i = 0; i < RowN; i++) { Result[i] = 0.0; }
00158     for (int i = 0; i < ColN; i++) {
00159         TLinAlg::AddVec(Vec[i], ColV[i], Result, Result);
00160     }
00161 }
00162 
00164 // Basic Linear Algebra Operations
00165 double TLinAlg::DotProduct(const TFltV& x, const TFltV& y) {
00166     IAssertR(x.Len() == y.Len(), TStr::Fmt("%d != %d", x.Len(), y.Len()));
00167     double result = 0.0; int Len = x.Len();
00168     for (int i = 0; i < Len; i++)
00169         result += x[i] * y[i];
00170     return result;
00171 }
00172 
00173 double TLinAlg::DotProduct(const TFltVV& X, int ColIdX, const TFltVV& Y, int ColIdY) {
00174     Assert(X.GetRows() == Y.GetRows());
00175     double result = 0.0, len = X.GetRows();
00176     for (int i = 0; i < len; i++)
00177         result = result + X(i,ColIdX) * Y(i,ColIdY);
00178     return result;
00179 }
00180 
00181 double TLinAlg::DotProduct(const TFltVV& X, int ColId, const TFltV& Vec) {
00182     Assert(X.GetRows() == Vec.Len());
00183     double result = 0.0; int Len = X.GetRows();
00184     for (int i = 0; i < Len; i++)
00185         result += X(i,ColId) * Vec[i];
00186     return result;
00187 }
00188 
00189 double TLinAlg::DotProduct(const TIntFltKdV& x, const TIntFltKdV& y) {
00190     const int xLen = x.Len(), yLen = y.Len();
00191     double Res = 0.0; int i1 = 0, i2 = 0;
00192     while (i1 < xLen && i2 < yLen) {
00193         if (x[i1].Key < y[i2].Key) i1++;
00194         else if (x[i1].Key > y[i2].Key) i2++;
00195         else { Res += x[i1].Dat * y[i2].Dat;  i1++;  i2++; }
00196     }
00197     return Res;
00198 }
00199 
00200 double TLinAlg::DotProduct(const TFltV& x, const TIntFltKdV& y) {
00201     double Res = 0.0; const int xLen = x.Len(), yLen = y.Len();
00202     for (int i = 0; i < yLen; i++) {
00203         const int key = y[i].Key;
00204         if (key < xLen) Res += y[i].Dat * x[key];
00205     }
00206     return Res;
00207 }
00208 
00209 double TLinAlg::DotProduct(const TFltVV& X, int ColId, const TIntFltKdV& y) {
00210     double Res = 0.0; const int n = X.GetRows(), yLen = y.Len();
00211     for (int i = 0; i < yLen; i++) {
00212         const int key = y[i].Key;
00213         if (key < n) Res += y[i].Dat * X(key,ColId);
00214     }
00215     return Res;
00216 }
00217 
00218 void TLinAlg::LinComb(const double& p, const TFltV& x,
00219         const double& q, const TFltV& y, TFltV& z) {
00220 
00221     Assert(x.Len() == y.Len() && y.Len() == z.Len());
00222     const int Len = x.Len();
00223     for (int i = 0; i < Len; i++) {
00224         z[i] = p * x[i] + q * y[i]; }
00225 }
00226 
00227 void TLinAlg::ConvexComb(const double& p, const TFltV& x, const TFltV& y, TFltV& z) {
00228     AssertR(0.0 <= p && p <= 1.0, TFlt::GetStr(p));
00229     LinComb(p, x, 1.0 - p, y, z);
00230 }
00231 
00232 void TLinAlg::AddVec(const double& k, const TFltV& x, const TFltV& y, TFltV& z) {
00233     LinComb(k, x, 1.0, y, z);
00234 }
00235 
00236 void TLinAlg::AddVec(const double& k, const TIntFltKdV& x, const TFltV& y, TFltV& z) {
00237     Assert(y.Len() == z.Len());
00238     z = y; // first we set z to be y
00239     // and than we add x to z (==y)
00240     const int xLen = x.Len(), yLen = y.Len();
00241     for (int i = 0; i < xLen; i++) {
00242         const int ii = x[i].Key;
00243         if (ii < yLen) {
00244             z[ii] = k * x[i].Dat + y[ii];
00245         }
00246     }
00247 }
00248 
00249 void TLinAlg::AddVec(const double& k, const TIntFltKdV& x, TFltV& y) {
00250     const int xLen = x.Len(), yLen = y.Len();
00251     for (int i = 0; i < xLen; i++) {
00252         const int ii = x[i].Key;
00253         if (ii < yLen) {
00254             y[ii] += k * x[i].Dat;
00255         }
00256     }
00257 }
00258 
00259 void TLinAlg::AddVec(double k, const TFltVV& X, int ColIdX, TFltVV& Y, int ColIdY){
00260     Assert(X.GetRows() == Y.GetRows());
00261     const int len = Y.GetRows();
00262     for (int i = 0; i < len; i++) {
00263         Y(i,ColIdY) = Y(i,ColIdY) + k * X(i, ColIdX);
00264     }
00265 }
00266 
00267 void TLinAlg::AddVec(double k, const TFltVV& X, int ColId, TFltV& Result){
00268     Assert(X.GetRows() == Result.Len());
00269     const int len = Result.Len();
00270     for (int i = 0; i < len; i++) {
00271         Result[i] = Result[i] + k * X(i, ColId);
00272     }
00273 }
00274 
00275 void TLinAlg::AddVec(const TIntFltKdV& x, const TIntFltKdV& y, TIntFltKdV& z) {
00276         TSparseOpsIntFlt::SparseMerge(x, y, z);
00277 }
00278 
00279 double TLinAlg::SumVec(const TFltV& x) {
00280     const int len = x.Len();
00281     double Res = 0.0;
00282     for (int i = 0; i < len; i++) {
00283         Res += x[i];
00284     }
00285     return Res;
00286 }
00287 
00288 double TLinAlg::SumVec(double k, const TFltV& x, const TFltV& y) {
00289     Assert(x.Len() == y.Len());
00290     const int len = x.Len();
00291     double Res = 0.0;
00292     for (int i = 0; i < len; i++) {
00293         Res += k * x[i] + y[i];
00294     }
00295     return Res;
00296 }
00297 
00298 double TLinAlg::EuclDist2(const TFltV& x, const TFltV& y) {
00299     Assert(x.Len() == y.Len());
00300     const int len = x.Len();
00301     double Res = 0.0;
00302     for (int i = 0; i < len; i++) {
00303         Res += TMath::Sqr(x[i] - y[i]);
00304     }
00305     return Res;
00306 }
00307 
00308 double TLinAlg::EuclDist(const TFltV& x, const TFltV& y) {
00309     return sqrt(EuclDist2(x, y));
00310 }
00311 
00312 double TLinAlg::Norm2(const TFltV& x) {
00313     return DotProduct(x, x);
00314 }
00315 
00316 double TLinAlg::Norm(const TFltV& x) {
00317     return sqrt(Norm2(x));
00318 }
00319 
00320 void TLinAlg::Normalize(TFltV& x) {
00321     const double xNorm = Norm(x);
00322     if (xNorm > 0.0) { MultiplyScalar(1/xNorm, x, x); }
00323 }
00324 
00325 double TLinAlg::Norm2(const TIntFltKdV& x) {
00326     double Result = 0;
00327     for (int i = 0; i < x.Len(); i++) {
00328         Result += TMath::Sqr(x[i].Dat);
00329     }
00330     return Result;
00331 }
00332 
00333 double TLinAlg::Norm(const TIntFltKdV& x) {
00334     return sqrt(Norm2(x));
00335 }
00336 
00337 void TLinAlg::Normalize(TIntFltKdV& x) {
00338     MultiplyScalar(1/Norm(x), x, x);
00339 }
00340 
00341 double TLinAlg::Norm2(const TFltVV& X, int ColId) {
00342     return DotProduct(X, ColId, X, ColId);
00343 }
00344 
00345 double TLinAlg::Norm(const TFltVV& X, int ColId) {
00346     return sqrt(Norm2(X, ColId));
00347 }
00348 
00349 double TLinAlg::NormL1(const TFltV& x) {
00350     double norm = 0.0; const int Len = x.Len();
00351     for (int i = 0; i < Len; i++)
00352         norm += TFlt::Abs(x[i]);
00353     return norm;
00354 }
00355 
00356 double TLinAlg::NormL1(double k, const TFltV& x, const TFltV& y) {
00357     Assert(x.Len() == y.Len());
00358     double norm = 0.0; const int len = x.Len();
00359     for (int i = 0; i < len; i++) {
00360         norm += TFlt::Abs(k * x[i] + y[i]);
00361     }
00362     return norm;
00363 }
00364 
00365 double TLinAlg::NormL1(const TIntFltKdV& x) {
00366     double norm = 0.0; const int Len = x.Len();
00367     for (int i = 0; i < Len; i++)
00368         norm += TFlt::Abs(x[i].Dat);
00369     return norm;
00370 }
00371 
00372 void TLinAlg::NormalizeL1(TFltV& x) {
00373     const double xNorm = NormL1(x);
00374     if (xNorm > 0.0) { MultiplyScalar(1/xNorm, x, x); }
00375 }
00376 
00377 void TLinAlg::NormalizeL1(TIntFltKdV& x) {
00378     const double xNorm = NormL1(x);
00379     if (xNorm > 0.0) { MultiplyScalar(1/xNorm, x, x); }
00380 }
00381 
00382 double TLinAlg::NormLinf(const TFltV& x) {
00383     double norm = 0.0; const int Len = x.Len();
00384     for (int i = 0; i < Len; i++)
00385         norm = TFlt::GetMx(TFlt::Abs(x[i]), norm);
00386     return norm;
00387 }
00388 
00389 double TLinAlg::NormLinf(const TIntFltKdV& x) {
00390     double norm = 0.0; const int Len = x.Len();
00391     for (int i = 0; i < Len; i++)
00392         norm = TFlt::GetMx(TFlt::Abs(x[i].Dat), norm);
00393     return norm;
00394 }
00395 
00396 void TLinAlg::NormalizeLinf(TFltV& x) {
00397     const double xNormLinf = NormLinf(x);
00398     if (xNormLinf > 0.0) { MultiplyScalar(1.0/xNormLinf, x, x); }
00399 }
00400 
00401 void TLinAlg::NormalizeLinf(TIntFltKdV& x) {
00402     const double xNormLInf = NormLinf(x);
00403     if (xNormLInf> 0.0) { MultiplyScalar(1.0/xNormLInf, x, x); }
00404 }
00405 
00406 void TLinAlg::MultiplyScalar(const double& k, const TFltV& x, TFltV& y) {
00407     Assert(x.Len() == y.Len());
00408     int Len = x.Len();
00409     for (int i = 0; i < Len; i++)
00410         y[i] = k * x[i];
00411 }
00412 
00413 void TLinAlg::MultiplyScalar(const double& k, const TIntFltKdV& x, TIntFltKdV& y) {
00414     Assert(x.Len() == y.Len());
00415     int Len = x.Len();
00416     for (int i = 0; i < Len; i++)
00417         y[i].Dat = k * x[i].Dat;
00418 }
00419 
00420 void TLinAlg::Multiply(const TFltVV& A, const TFltV& x, TFltV& y) {
00421     Assert(A.GetCols() == x.Len() && A.GetRows() == y.Len());
00422     int n = A.GetRows(), m = A.GetCols();
00423     for (int i = 0; i < n; i++) {
00424         y[i] = 0.0;
00425         for (int j = 0; j < m; j++)
00426             y[i] += A(i,j) * x[j];
00427     }
00428 }
00429 
00430 void TLinAlg::Multiply(const TFltVV& A, const TFltV& x, TFltVV& C, int ColId) {
00431     Assert(A.GetCols() == x.Len() && A.GetRows() == C.GetRows());
00432     int n = A.GetRows(), m = A.GetCols();
00433     for (int i = 0; i < n; i++) {
00434         C(i,ColId) = 0.0;
00435         for (int j = 0; j < m; j++)
00436             C(i,ColId) += A(i,j) * x[j];
00437     }
00438 }
00439 
00440 void TLinAlg::Multiply(const TFltVV& A, const TFltVV& B, int ColId, TFltV& y) {
00441     Assert(A.GetCols() == B.GetRows() && A.GetRows() == y.Len());
00442     int n = A.GetRows(), m = A.GetCols();
00443     for (int i = 0; i < n; i++) {
00444         y[i] = 0.0;
00445         for (int j = 0; j < m; j++)
00446             y[i] += A(i,j) * B(j,ColId);
00447     }
00448 }
00449 
00450 void TLinAlg::Multiply(const TFltVV& A, const TFltVV& B, int ColIdB, TFltVV& C, int ColIdC){
00451     Assert(A.GetCols() == B.GetRows() && A.GetRows() == C.GetRows());
00452     int n = A.GetRows(), m = A.GetCols();
00453     for (int i = 0; i < n; i++) {
00454         C(i,ColIdC) = 0.0;
00455         for (int j = 0; j < m; j++)
00456             C(i,ColIdC) += A(i,j) * B(j,ColIdB);
00457     }
00458 }
00459 
00460 void TLinAlg::MultiplyT(const TFltVV& A, const TFltV& x, TFltV& y) {
00461     Assert(A.GetRows() == x.Len() && A.GetCols() == y.Len());
00462     int n = A.GetCols(), m = A.GetRows();
00463     for (int i = 0; i < n; i++) {
00464         y[i] = 0.0;
00465         for (int j = 0; j < m; j++)
00466             y[i] += A(j,i) * x[j];
00467     }
00468 }
00469 
00470 void TLinAlg::Multiply(const TFltVV& A, const TFltVV& B, TFltVV& C) {
00471     Assert(A.GetRows() == C.GetRows() && B.GetCols() == C.GetCols() && A.GetCols() == B.GetRows());
00472 
00473     int n = C.GetRows(), m = C.GetCols(), l = A.GetCols();
00474     for (int i = 0; i < n; i++) {
00475         for (int j = 0; j < m; j++) {
00476             double sum = 0.0;
00477             for (int k = 0; k < l; k++)
00478                 sum += A(i,k)*B(k,j);
00479             C(i,j) = sum;
00480         }
00481     }
00482 }
00483 
00484 // general matrix multiplication (GEMM)
00485 void TLinAlg::Gemm(const double& Alpha, const TFltVV& A, const TFltVV& B, const double& Beta, 
00486                 const TFltVV& C, TFltVV& D, const int& TransposeFlags) {
00487 
00488         bool tA = (TransposeFlags & GEMM_A_T) == GEMM_A_T;
00489         bool tB = (TransposeFlags & GEMM_B_T) == GEMM_B_T;
00490         bool tC = (TransposeFlags & GEMM_C_T) == GEMM_C_T;
00491 
00492         // setting dimensions
00493         int a_i = tA ? A.GetRows() : A.GetCols();
00494         int a_j = tA ? A.GetCols() : A.GetRows();
00495 
00496         int b_i = tB ? A.GetRows() : A.GetCols();
00497         int b_j = tB ? A.GetCols() : A.GetRows();
00498 
00499         int c_i = tC ? A.GetRows() : A.GetCols();
00500         int c_j = tC ? A.GetCols() : A.GetRows();
00501 
00502         int d_i = D.GetCols();
00503         int d_j = D.GetRows();
00504         
00505         // assertions for dimensions
00506         Assert(a_i == c_j && b_i == c_i && a_i == b_j && c_i == d_i && c_j == d_j);
00507 
00508         double Aij, Bij, Cij;
00509 
00510         // rows
00511         for (int j = 0; j < a_j; j++) {
00512                 // cols
00513                 for (int i = 0; i < a_i; i++) {
00514                         // not optimized for speed (!)
00515                         double sum = 0;
00516                         for (int k = 0; k < a_i; k++) {
00517                                 Aij = tA ? A.At(j, k) : A.At(k, j);
00518                                 Bij = tB ? B.At(k, i) : B.At(i, k);
00519                                 sum += Alpha * Aij * Bij;
00520                         }
00521                         Cij = tC ? C.At(i, j) : C.At(j, i);
00522                         sum += Beta * Cij;
00523                         D.At(i, j) = sum;
00524                 }
00525         }
00526 }
00527 
00528 void TLinAlg::Transpose(const TFltVV& A, TFltVV& B) {
00529         Assert(B.GetRows() == A.GetCols() && B.GetCols() == A.GetRows());
00530         for (int j = 0; j < A.GetRows(); j++) {
00531                 for (int i = 0; i < B.GetCols(); i++) {
00532                         B.At(j, i) = A.At(i, j);
00533                 }
00534         }
00535 }
00536 
00537 void TLinAlg::Inverse(const TFltVV& A, TFltVV& B, const TLinAlgInverseType& DecompType) {
00538         switch (DecompType) {
00539                 case DECOMP_SVD:
00540                         InverseSVD(A, B);
00541         }
00542 }
00543 
00544 void TLinAlg::InverseSVD(const TFltVV& M, TFltVV& B) {
00545         // create temp matrices
00546         TFltVV U, V;
00547         TFltV E;
00548         TSvd SVD;
00549 
00550         U.Gen(M.GetRows(), M.GetRows());        
00551         V.Gen(M.GetCols(), M.GetCols());
00552 
00553         // do the SVD decompostion
00554         SVD.Svd(M, U, E, V);
00555 
00556         // calculate reciprocal values for diagonal matrix = inverse diagonal
00557         for (int i = 0; i < E.Len(); i++) {
00558                 E[i] = 1 / E[i];
00559         }
00560 
00561         // calculate pseudoinverse: M^(-1) = V * E^(-1) * U'
00562         for (int i = 0; i < U.GetCols(); i++) {
00563                 for (int j = 0; j < V.GetRows(); j++) {
00564                         double sum = 0;
00565                         for (int k = 0; k < U.GetCols(); k++) {
00566                                 sum += E[k] * V.At(i, k) * U.At(j, k);
00567                         }
00568                         B.At(i, j) = sum;
00569                 }
00570         }       
00571 }
00572 
00573 void TLinAlg::GS(TVec<TFltV>& Q) {
00574     IAssert(Q.Len() > 0);
00575     int m = Q.Len(); // int n = Q[0].Len();
00576     for (int i = 0; i < m; i++) {
00577         printf("%d\r",i);
00578         for (int j = 0; j < i; j++) {
00579             double r = TLinAlg::DotProduct(Q[i], Q[j]);
00580             TLinAlg::AddVec(-r,Q[j],Q[i],Q[i]);
00581         }
00582         TLinAlg::Normalize(Q[i]);
00583     }
00584     printf("\n");
00585 }
00586 
00587 void TLinAlg::GS(TFltVV& Q) {
00588     int m = Q.GetCols(), n = Q.GetRows();
00589     for (int i = 0; i < m; i++) {
00590         for (int j = 0; j < i; j++) {
00591             double r = TLinAlg::DotProduct(Q, i, Q, j);
00592             TLinAlg::AddVec(-r,Q,j,Q,i);
00593         }
00594         double nr = TLinAlg::Norm(Q,i);
00595         for (int k = 0; k < n; k++)
00596             Q(k,i) = Q(k,i) / nr;
00597     }
00598 }
00599 
00600 void TLinAlg::Rotate(const double& OldX, const double& OldY, const double& Angle, double& NewX, double& NewY) {
00601     NewX = OldX*cos(Angle) - OldY*sin(Angle);
00602     NewY = OldX*sin(Angle) + OldY*cos(Angle);
00603 }
00604 
00605 void TLinAlg::AssertOrtogonality(const TVec<TFltV>& Vecs, const double& Threshold) {
00606     int m = Vecs.Len();
00607     for (int i = 0; i < m; i++) {
00608         for (int j = 0; j < i; j++) {
00609             double res = DotProduct(Vecs[i], Vecs[j]);
00610             if (TFlt::Abs(res) > Threshold)
00611                 printf("<%d,%d> = %.5f", i,j,res);
00612         }
00613         double norm = Norm2(Vecs[i]);
00614         if (TFlt::Abs(norm-1) > Threshold)
00615             printf("||%d|| = %.5f", i, norm);
00616     }
00617 }
00618 
00619 void TLinAlg::AssertOrtogonality(const TFltVV& Vecs, const double& Threshold) {
00620     int m = Vecs.GetCols();
00621     for (int i = 0; i < m; i++) {
00622         for (int j = 0; j < i; j++) {
00623             double res = DotProduct(Vecs, i, Vecs, j);
00624             if (TFlt::Abs(res) > Threshold)
00625                 printf("<%d,%d> = %.5f", i, j, res);
00626         }
00627         double norm = Norm2(Vecs, i);
00628         if (TFlt::Abs(norm-1) > Threshold)
00629             printf("||%d|| = %.5f", i, norm);
00630     }
00631     printf("\n");
00632 }
00633 
00635 // Numerical Linear Algebra
00636 double TNumericalStuff::sqr(double a) {
00637   return a == 0.0 ? 0.0 : a*a;
00638 }
00639 
00640 double TNumericalStuff::sign(double a, double b) {
00641   return b >= 0.0 ? fabs(a) : -fabs(a);
00642 }
00643 
00644 void TNumericalStuff::nrerror(const TStr& error_text) {
00645     printf("NR_ERROR: %s", error_text.CStr());
00646     throw new TNSException(error_text);
00647 }
00648 
00649 double TNumericalStuff::pythag(double a, double b) {
00650     double absa = fabs(a), absb = fabs(b);
00651     if (absa > absb)
00652         return absa*sqrt(1.0+sqr(absb/absa));
00653     else
00654         return (absb == 0.0 ? 0.0 : absb*sqrt(1.0+sqr(absa/absb)));
00655 }
00656 
00657 void TNumericalStuff::SymetricToTridiag(TFltVV& a, int n, TFltV& d, TFltV& e) {
00658     int l,k,j,i;
00659     double scale,hh,h,g,f;
00660     for (i=n;i>=2;i--) {
00661         l=i-1;
00662         h=scale=0.0;
00663         if (l > 1) {
00664             for (k=1;k<=l;k++)
00665                 scale += fabs(a(i-1,k-1).Val);
00666             if (scale == 0.0) //Skip transformation.
00667                 e[i]=a(i-1,l-1);
00668             else {
00669                 for (k=1;k<=l;k++) {
00670                     a(i-1,k-1) /= scale; //Use scaled a's for transformation.
00671                     h += a(i-1,k-1)*a(i-1,k-1);
00672                 }
00673                 f=a(i-1,l-1);
00674                 g=(f >= 0.0 ? -sqrt(h) : sqrt(h));
00675                 IAssertR(_isnan(g) == 0, TFlt::GetStr(h));
00676                 e[i]=scale*g;
00677                 h -= f*g; //Now h is equation (11.2.4).
00678                 a(i-1,l-1)=f-g; //Store u in the ith row of a.
00679                 f=0.0;
00680                 for (j=1;j<=l;j++) {
00681                     // Next statement can be omitted if eigenvectors not wanted
00682                     a(j-1,i-1)=a(i-1,j-1)/h; //Store u=H in ith column of a.
00683                     g=0.0; //Form an element of A  u in g.
00684                     for (k=1;k<=j;k++)
00685                         g += a(j-1,k-1)*a(i-1,k-1);
00686                     for (k=j+1;k<=l;k++)
00687                         g += a(k-1,j-1)*a(i-1,k-1);
00688                     e[j]=g/h; //Form element of p in temporarily unused element of e.
00689                     f += e[j]*a(i-1,j-1);
00690                 }
00691                 hh=f/(h+h); //Form K, equation (11.2.11).
00692                 for (j=1;j<=l;j++) { //Form q and store in e overwriting p.
00693                     f=a(i-1,j-1);
00694                     e[j]=g=e[j]-hh*f;
00695                     for (k=1;k<=j;k++) { //Reduce a, equation (11.2.13).
00696                         a(j-1,k-1) -= (f*e[k]+g*a(i-1,k-1));
00697                         Assert(_isnan(a(j-1,k-1)) == 0);
00698                     }
00699                 }
00700             }
00701         } else
00702             e[i]=a(i-1,l-1);
00703         d[i]=h;
00704     }
00705     // Next statement can be omitted if eigenvectors not wanted
00706     d[1]=0.0;
00707     e[1]=0.0;
00708     // Contents of this loop can be omitted if eigenvectors not
00709     // wanted except for statement d[i]=a[i][i];
00710     for (i=1;i<=n;i++) { //Begin accumulation of transformationmatrices.
00711         l=i-1;
00712         if (d[i]) { //This block skipped when i=1.
00713             for (j=1;j<=l;j++) {
00714                 g=0.0;
00715                 for (k=1;k<=l;k++) //Use u and u=H stored in a to form PQ.
00716                     g += a(i-1,k-1)*a(k-1,j-1);
00717                 for (k=1;k<=l;k++) {
00718                     a(k-1,j-1) -= g*a(k-1,i-1);
00719                     Assert(_isnan(a(k-1,j-1)) == 0);
00720                 }
00721             }
00722         }
00723         d[i]=a(i-1,i-1); //This statement remains.
00724         a(i-1,i-1)=1.0; //Reset row and column of a to identity  matrix for next iteration.
00725         for (j=1;j<=l;j++) a(j-1,i-1)=a(i-1,j-1)=0.0;
00726     }
00727 }
00728 
00729 void TNumericalStuff::EigSymmetricTridiag(TFltV& d, TFltV& e, int n, TFltVV& z) {
00730     int m,l,iter,i,k; // N = n+1;
00731     double s,r,p,g,f,dd,c,b;
00732     // Convenient to renumber the elements of e
00733     for (i=2;i<=n;i++) e[i-1]=e[i];
00734     e[n]=0.0;
00735     for (l=1;l<=n;l++) {
00736         iter=0;
00737         do {
00738             // Look for a single small subdiagonal element to split the matrix.
00739             for (m=l;m<=n-1;m++) {
00740         dd=TFlt::Abs(d[m])+TFlt::Abs(d[m+1]);
00741                 if ((double)(TFlt::Abs(e[m])+dd) == dd) break;
00742             }
00743             if (m != l) {
00744                 if (iter++ == 60) nrerror("Too many iterations in EigSymmetricTridiag");
00745                 //Form shift.
00746                 g=(d[l+1]-d[l])/(2.0*e[l]);
00747                 r=pythag(g,1.0);
00748                 //This is dm - ks.
00749                 g=d[m]-d[l]+e[l]/(g+sign(r,g));
00750                 s=c=1.0;
00751                 p=0.0;
00752                 // A plane rotation as in the original QL, followed by
00753                 // Givens rotations to restore tridiagonal form
00754                 for (i=m-1;i>=l;i--) {
00755                     f=s*e[i];
00756                     b=c*e[i];
00757                     e[i+1]=(r=pythag(f,g));
00758                     // Recover from underflow.
00759                     if (r == 0.0) {
00760                         d[i+1] -= p;
00761                         e[m]=0.0;
00762                         break;
00763                     }
00764                     s=f/r;
00765                     c=g/r;
00766                     g=d[i+1]-p;
00767                     r=(d[i]-g)*s+2.0*c*b;
00768                     d[i+1]=g+(p=s*r);
00769                     g=c*r-b;
00770                     // Next loop can be omitted if eigenvectors not wanted
00771                     for (k=0;k<n;k++) {
00772                         f=z(k,i);
00773                         z(k,i)=s*z(k,i-1)+c*f;
00774                         z(k,i-1)=c*z(k,i-1)-s*f;
00775                     }
00776                 }
00777                 if (r == 0.0 && i >= l) continue;
00778                 d[l] -= p;
00779                 e[l]=g;
00780                 e[m]=0.0;
00781             }
00782         } while (m != l);
00783     }
00784 }
00785 
00786 void TNumericalStuff::CholeskyDecomposition(TFltVV& A, TFltV& p) {
00787   Assert(A.GetRows() == A.GetCols());
00788   int n = A.GetRows(); p.Reserve(n,n);
00789 
00790   int i,j,k;
00791   double sum;
00792   for (i=1;i<=n;i++) {
00793     for (j=i;j<=n;j++) {
00794       for (sum=A(i-1,j-1),k=i-1;k>=1;k--) sum -= A(i-1,k-1)*A(j-1,k-1);
00795       if (i == j) {
00796         if (sum <= 0.0)
00797           nrerror("choldc failed");
00798         p[i-1]=sqrt(sum);
00799       } else A(j-1,i-1)=sum/p[i-1];
00800     }
00801   }
00802 }
00803 
00804 void TNumericalStuff::CholeskySolve(const TFltVV& A, const TFltV& p, const TFltV& b, TFltV& x) {
00805   IAssert(A.GetRows() == A.GetCols());
00806   int n = A.GetRows(); x.Reserve(n,n);
00807 
00808   int i,k;
00809   double sum;
00810 
00811   // Solve L * y = b, storing y in x
00812   for (i=1;i<=n;i++) {
00813     for (sum=b[i-1],k=i-1;k>=1;k--)
00814       sum -= A(i-1,k-1)*x[k-1];
00815     x[i-1]=sum/p[i-1];
00816   }
00817 
00818   // Solve L^T * x = y
00819   for (i=n;i>=1;i--) {
00820     for (sum=x[i-1],k=i+1;k<=n;k++)
00821       sum -= A(k-1,i-1)*x[k-1];
00822     x[i-1]=sum/p[i-1];
00823   }
00824 }
00825 
00826 void TNumericalStuff::SolveSymetricSystem(TFltVV& A, const TFltV& b, TFltV& x) {
00827   IAssert(A.GetRows() == A.GetCols());
00828   TFltV p; CholeskyDecomposition(A, p);
00829   CholeskySolve(A, p, b, x);
00830 }
00831 
00832 void TNumericalStuff::InverseSubstitute(TFltVV& A, const TFltV& p) {
00833   IAssert(A.GetRows() == A.GetCols());
00834   int n = A.GetRows(); TFltV x(n);
00835 
00836     int i, j, k; double sum;
00837     for (i = 0; i < n; i++) {
00838       // solve L * y = e_i, store in x
00839         // elements from 0 to i-1 are 0.0
00840         for (j = 0; j < i; j++) x[j] = 0.0;
00841         // solve l_ii * y_i = 1 => y_i = 1/l_ii
00842         x[i] = 1/p[i];
00843         // solve y_j for j > i
00844         for (j = i+1; j < n; j++) {
00845             for (sum = 0.0, k = i; k < j; k++)
00846                 sum -= A(j,k) * x[k];
00847             x[j] = sum / p[j];
00848         }
00849 
00850       // solve L'* x = y, store in upper triangule of A
00851         for (j = n-1; j >= i; j--) {
00852             for (sum = x[j], k = j+1; k < n; k++)
00853                 sum -= A(k,j)*x[k];
00854             x[j] = sum/p[j];
00855         }
00856         for (int j = i; j < n; j++) A(i,j) = x[j];
00857     }
00858 
00859 }
00860 
00861 void TNumericalStuff::InverseSymetric(TFltVV& A) {
00862     IAssert(A.GetRows() == A.GetCols());
00863     TFltV p;
00864     // first we calculate cholesky decomposition of A
00865     CholeskyDecomposition(A, p);
00866     // than we solve system A x_i = e_i for i = 1..n
00867     InverseSubstitute(A, p);
00868 }
00869 
00870 void TNumericalStuff::InverseTriagonal(TFltVV& A) {
00871   IAssert(A.GetRows() == A.GetCols());
00872   int n = A.GetRows(); TFltV x(n), p(n);
00873 
00874     int i, j, k; double sum;
00875     // copy upper triangle to lower one as we'll overwrite upper one
00876     for (i = 0; i < n; i++) {
00877         p[i] = A(i,i);
00878         for (j = i+1; j < n; j++)
00879             A(j,i) = A(i,j);
00880     }
00881     // solve
00882     for (i = 0; i < n; i++) {
00883         // solve R * x = e_i, store in x
00884         // elements from 0 to i-1 are 0.0
00885         for (j = n-1; j > i; j--) x[j] = 0.0;
00886         // solve l_ii * y_i = 1 => y_i = 1/l_ii
00887         x[i] = 1/p[i];
00888         // solve y_j for j > i
00889         for (j = i-1; j >= 0; j--) {
00890             for (sum = 0.0, k = i; k > j; k--)
00891                 sum -= A(k,j) * x[k];
00892             x[j] = sum / p[j];
00893         }
00894         for (int j = 0; j <= i; j++) A(j,i) = x[j];
00895     }
00896 }
00897 
00898 void TNumericalStuff::LUDecomposition(TFltVV& A, TIntV& indx, double& d) {
00899   Assert(A.GetRows() == A.GetCols());
00900   int n = A.GetRows(); indx.Reserve(n,n);
00901 
00902     int i=0,imax=0,j=0,k=0;
00903     double big,dum,sum,temp;
00904     TFltV vv(n); // vv stores the implicit scaling of each row.
00905     d=1.0;       // No row interchanges yet.
00906 
00907     // Loop over rows to get the implicit scaling information.
00908     for (i=1;i<=n;i++) {
00909         big=0.0;
00910         for (j=1;j<=n;j++)
00911             if ((temp=TFlt::Abs(A(i-1,j-1))) > big) big=temp;
00912         if (big == 0.0) nrerror("Singular matrix in routine LUDecomposition");
00913         vv[i-1]=1.0/big;
00914     }
00915 
00916     for (j=1;j<=n;j++) {
00917         for (i=1;i<j;i++) {
00918             sum=A(i-1,j-1);
00919             for (k=1;k<i;k++) sum -= A(i-1,k-1)*A(k-1,j-1);
00920             A(i-1,j-1)=sum;
00921         }
00922         big=0.0; //Initialize for the search for largest pivot element.
00923         for (i=j;i<=n;i++) {
00924             sum=A(i-1,j-1);
00925             for (k=1;k<j;k++)
00926                 sum -= A(i-1,k-1)*A(k-1,j-1);
00927             A(i-1,j-1)=sum;
00928 
00929             //Is the figure of merit for the pivot better than the best so far?
00930             if ((dum=vv[i-1] * TFlt::Abs(sum)) >= big) {
00931                 big=dum;
00932                 imax=i;
00933             }
00934         }
00935 
00936         //Do we need to interchange rows?
00937         if (j != imax) {
00938             //Yes, do so...
00939             for (k=1;k<=n;k++) {
00940                 dum=A(imax-1,k-1);
00941             A(imax-1,k-1)=A(j-1,k-1); // Tadej: imax-1,k looks wrong
00942             A(j-1,k-1)=dum;
00943             }
00944             //...and change the parity of d.
00945             d = -d;
00946             vv[imax-1]=vv[j-1]; //Also interchange the scale factor.
00947         }
00948         indx[j-1]=imax;
00949 
00950         //If the pivot element is zero the matrix is singular (at least to the precision of the
00951         //algorithm). For some applications on singular matrices, it is desirable to substitute
00952         //TINY for zero.
00953         if (A(j-1,j-1) == 0.0) A(j-1,j-1)=1e-20;
00954 
00955          //Now, finally, divide by the pivot element.
00956         if (j != n) {
00957             dum=1.0/(A(j-1,j-1));
00958             for (i=j+1;i<=n;i++) A(i-1,j-1) *= dum;
00959         }
00960     } //Go back for the next column in the reduction.
00961 }
00962 
00963 void TNumericalStuff::LUSolve(const TFltVV& A, const TIntV& indx, TFltV& b) {
00964   Assert(A.GetRows() == A.GetCols());
00965   int n = A.GetRows();
00966     int i,ii=0,ip,j;
00967     double sum;
00968     for (i=1;i<=n;i++) {
00969         ip=indx[i-1];
00970         sum=b[ip-1];
00971         b[ip-1]=b[i-1];
00972         if (ii)
00973             for (j=ii;j<=i-1;j++) sum -= A(i-1,j-1)*b[j-1];
00974         else if (sum) ii=i;b[i-1]=sum;
00975     }
00976     for (i=n;i>=1;i--) {
00977         sum=b[i-1];
00978         for (j=i+1;j<=n;j++) sum -= A(i-1,j-1)*b[j-1];
00979         b[i-1]=sum/A(i-1,i-1);
00980     }
00981 }
00982 
00983 void TNumericalStuff::SolveLinearSystem(TFltVV& A, const TFltV& b, TFltV& x) {
00984     TIntV indx; double d;
00985     LUDecomposition(A, indx, d);
00986     x = b;
00987     LUSolve(A, indx, x);
00988 }
00989 
00991 // Sparse-SVD
00992 void TSparseSVD::MultiplyATA(const TMatrix& Matrix,
00993         const TFltVV& Vec, int ColId, TFltV& Result) {
00994     TFltV tmp(Matrix.GetRows());
00995     // tmp = A * Vec(:,ColId)
00996     Matrix.Multiply(Vec, ColId, tmp);
00997     // Vec = A' * tmp
00998     Matrix.MultiplyT(tmp, Result);
00999 }
01000 
01001 void TSparseSVD::MultiplyATA(const TMatrix& Matrix,
01002         const TFltV& Vec, TFltV& Result) {
01003     TFltV tmp(Matrix.GetRows());
01004     // tmp = A * Vec
01005     Matrix.Multiply(Vec, tmp);
01006     // Vec = A' * tmp
01007     Matrix.MultiplyT(tmp, Result);
01008 }
01009 
01010 void TSparseSVD::OrtoIterSVD(const TMatrix& Matrix,
01011         int NumSV, int IterN, TFltV& SgnValV) {
01012 
01013     int i, j, k;
01014     int N = Matrix.GetCols(), M = NumSV;
01015     TFltVV Q(N, M);
01016 
01017     // Q = rand(N,M)
01018     TRnd rnd;
01019     for (i = 0; i < N; i++) {
01020         for (j = 0; j < M; j++)
01021             Q(i,j) = rnd.GetUniDev();
01022     }
01023 
01024     TFltV tmp(N);
01025     for (int IterC = 0; IterC < IterN; IterC++) {
01026         printf("%d..", IterC);
01027         // Gram-Schmidt
01028         TLinAlg::GS(Q);
01029         // Q = A'*A*Q
01030         for (int ColId = 0; ColId < M; ColId++) {
01031             MultiplyATA(Matrix, Q, ColId, tmp);
01032             for (k = 0; k < N; k++) Q(k,ColId) = tmp[k];
01033         }
01034     }
01035 
01036     SgnValV.Reserve(NumSV,0);
01037     for (i = 0; i < NumSV; i++)
01038         SgnValV.Add(sqrt(TLinAlg::Norm(Q,i)));
01039     TLinAlg::GS(Q);
01040 }
01041 
01042 void TSparseSVD::SimpleLanczos(const TMatrix& Matrix,
01043         const int& NumEig, TFltV& EigValV,
01044         const bool& DoLocalReortoP, const bool& SvdMatrixProductP) {
01045 
01046     if (SvdMatrixProductP) {
01047         // if this fails, use transposed matrix
01048         IAssert(Matrix.GetRows() >= Matrix.GetCols());
01049     } else {
01050         IAssert(Matrix.GetRows() == Matrix.GetCols());
01051     }
01052 
01053     const int N = Matrix.GetCols(); // size of matrix
01054     TFltV r(N), v0(N), v1(N); // current vector and 2 previous ones
01055     TFltV alpha(NumEig, 0), beta(NumEig, 0); // diagonal and subdiagonal of T
01056 
01057     printf("Calculating %d eigen-values of %d x %d matrix\n", NumEig, N, N);
01058 
01059     // set starting vector
01060     //TRnd Rnd(0);
01061     for (int i = 0; i < N; i++) {
01062         r[i] = 1/sqrt((double)N); // Rnd.GetNrmDev();
01063         v0[i] = v1[i] = 0.0;
01064     }
01065     beta.Add(TLinAlg::Norm(r));
01066 
01067     for (int j = 0; j < NumEig; j++) {
01068         printf("%d\r", j+1);
01069         // v_j -> v_(j-1)
01070         v0 = v1;
01071         // v_j = (1/beta_(j-1)) * r
01072         TLinAlg::MultiplyScalar(1/beta[j], r, v1);
01073         // r = A*v_j
01074         if (SvdMatrixProductP) {
01075             // A = Matrix'*Matrix
01076             MultiplyATA(Matrix, v1, r);
01077         } else {
01078             // A = Matrix
01079             Matrix.Multiply(v1, r);
01080         }
01081         // r = r - beta_(j-1) * v_(j-1)
01082         TLinAlg::AddVec(-beta[j], v0, r, r);
01083         // alpha_j = vj'*r
01084         alpha.Add(TLinAlg::DotProduct(v1, r));
01085         // r = r - v_j * alpha_j
01086         TLinAlg::AddVec(-alpha[j], v1, r, r);
01087         // reortogonalization if neessary
01088         if (DoLocalReortoP) { } //TODO
01089         // beta_j = ||r||_2
01090         beta.Add(TLinAlg::Norm(r));
01091         // compoute approximatie eigenvalues T_j
01092         // test bounds for convergence
01093     }
01094     printf("\n");
01095 
01096     // prepare matrix T
01097     TFltV d(NumEig + 1), e(NumEig + 1);
01098     d[1] = alpha[0]; d[0] = e[0] = e[1] = 0.0;
01099     for (int i = 1; i < NumEig; i++) {
01100         d[i+1] = alpha[i]; e[i+1] = beta[i]; }
01101     // solve eigne problem for tridiagonal matrix with diag d and subdiag e
01102     TFltVV S(NumEig+1,NumEig+1); // eigen-vectors
01103     TLAMisc::FillIdentity(S); // make it identity
01104     TNumericalStuff::EigSymmetricTridiag(d, e, NumEig, S); // solve
01105     //TLAMisc::PrintTFltV(d, "AllEigV");
01106 
01107     // check convergence
01108     TFltKdV AllEigValV(NumEig, 0);
01109     for (int i = 1; i <= NumEig; i++) {
01110         const double ResidualNorm = TFlt::Abs(S(i-1, NumEig-1) * beta.Last());
01111         if (ResidualNorm < 1e-5)
01112             AllEigValV.Add(TFltKd(TFlt::Abs(d[i]), d[i]));
01113     }
01114 
01115     // prepare results
01116     AllEigValV.Sort(false); EigValV.Gen(NumEig, 0);
01117     for (int i = 0; i < AllEigValV.Len(); i++) {
01118         if (i == 0 || (TFlt::Abs(AllEigValV[i].Dat/AllEigValV[i-1].Dat) < 0.9999))
01119             EigValV.Add(AllEigValV[i].Dat);
01120     }
01121 }
01122 
01123 void TSparseSVD::Lanczos(const TMatrix& Matrix, int NumEig,
01124         int Iters, const TSpSVDReOrtoType& ReOrtoType,
01125         TFltV& EigValV, TFltVV& EigVecVV, const bool& SvdMatrixProductP) {
01126 
01127     if (SvdMatrixProductP) {
01128         // if this fails, use transposed matrix
01129         IAssert(Matrix.GetRows() >= Matrix.GetCols());
01130     } else {
01131         IAssert(Matrix.GetRows() == Matrix.GetCols());
01132     }
01133   IAssertR(NumEig <= Iters, TStr::Fmt("%d <= %d", NumEig, Iters));
01134 
01135     //if (ReOrtoType == ssotFull) printf("Full reortogonalization\n");
01136     int i, N = Matrix.GetCols(), K; // K - current dimension of T
01137     double t = 0.0, eps = 1e-6; // t - 1-norm of T
01138 
01139     //sequence of Ritz's vectors
01140     TFltVV Q(N, Iters);
01141     double tmp = 1/sqrt((double)N);
01142     for (i = 0; i < N; i++)
01143         Q(i,0) = tmp;
01144     //converget Ritz's vectors
01145     TVec<TFltV> ConvgQV(Iters);
01146     TIntV CountConvgV(Iters);
01147     for (i = 0; i < Iters; i++) CountConvgV[i] = 0;
01148     // const int ConvgTreshold = 50;
01149 
01150     //diagonal and subdiagonal of T
01151     TFltV d(Iters+1), e(Iters+1);
01152     //eigenvectors of T
01153     //TFltVV V;
01154     TFltVV V(Iters, Iters);
01155 
01156     // z - current Lanczos's vector
01157     TFltV z(N), bb(Iters), aa(Iters), y(N);
01158     //printf("svd(%d,%d)...\n", NumEig, Iters);
01159 
01160     if (SvdMatrixProductP) {
01161         // A = Matrix'*Matrix
01162         MultiplyATA(Matrix, Q, 0, z);
01163     } else {
01164         // A = Matrix
01165         Matrix.Multiply(Q, 0, z);
01166     }
01167 
01168     for (int j = 0; j < (Iters-1); j++) {
01169         //printf("%d..\r",j+2);
01170 
01171         //calculates (j+1)-th Lanczos's vector
01172         // aa[j] = <Q(:,j), z>
01173         aa[j] = TLinAlg::DotProduct(Q, j, z);
01174         //printf(" %g -- ", aa[j].Val); //HACK
01175 
01176         TLinAlg::AddVec(-aa[j], Q, j, z);
01177         if (j > 0) {
01178             // z := -aa[j] * Q(:,j) + z
01179             TLinAlg::AddVec(-bb[j-1], Q, j-1, z);
01180 
01181             //reortogonalization
01182             if (ReOrtoType == ssotSelective || ReOrtoType == ssotFull) {
01183                 for (i = 0; i <= j; i++) {
01184                     // if i-tj vector converget, than we have to ortogonalize against it
01185                     if ((ReOrtoType == ssotFull) ||
01186                         (bb[j-1] * TFlt::Abs(V(K-1, i)) < eps * t)) {
01187 
01188                         ConvgQV[i].Reserve(N,N); CountConvgV[i]++;
01189                         TFltV& vec = ConvgQV[i];
01190                         //vec = Q * V(:,i)
01191                         for (int k = 0; k < N; k++) {
01192                             vec[k] = 0.0;
01193                             for (int l = 0; l < K; l++)
01194                                 vec[k] += Q(k,l) * V(l,i);
01195                         }
01196                         TLinAlg::AddVec(-TLinAlg::DotProduct(ConvgQV[i], z), ConvgQV[i], z ,z);
01197                     }
01198                 }
01199             }
01200         }
01201 
01202         //adds (j+1)-th Lanczos's vector to Q
01203         bb[j] = TLinAlg::Norm(z);
01204     if (!(bb[j] > 1e-10)) {
01205       printf("Rank of matrix is only %d\n", j+2);
01206       printf("Last singular value is %g\n", bb[j].Val);
01207       break;
01208     }
01209         for (i = 0; i < N; i++)
01210             Q(i, j+1) = z[i] / bb[j];
01211 
01212         //next Lanzcos vector
01213         if (SvdMatrixProductP) {
01214             // A = Matrix'*Matrix
01215             MultiplyATA(Matrix, Q, j+1, z);
01216         } else {
01217             // A = Matrix
01218             Matrix.Multiply(Q, j+1, z);
01219         }
01220 
01221         //calculate T (K x K matrix)
01222         K = j + 2;
01223         // calculate diagonal
01224         for (i = 1; i < K; i++) d[i] = aa[i-1];
01225         d[K] = TLinAlg::DotProduct(Q, K-1, z);
01226         // calculate subdiagonal
01227         e[1] = 0.0;
01228         for (i = 2; i <= K; i++) e[i] = bb[i-2];
01229 
01230         //calculate 1-norm of T
01231         t = TFlt::GetMx(TFlt::Abs(d[1]) + TFlt::Abs(e[2]), TFlt::Abs(e[K]) + TFlt::Abs(d[K]));
01232         for (i = 2; i < K; i++)
01233             t = TFlt::GetMx(t, TFlt::Abs(e[i]) + TFlt::Abs(d[i]) + TFlt::Abs(e[i+1]));
01234 
01235         //set V to identity matrix
01236         //V.Gen(K,K);
01237         for (i = 0; i < K; i++) {
01238             for (int k = 0; k < K; k++)
01239                 V(i,k) = 0.0;
01240             V(i,i) = 1.0;
01241         }
01242 
01243         //eigenvectors of T
01244         TNumericalStuff::EigSymmetricTridiag(d, e, K, V);
01245     }//for
01246     //printf("\n");
01247 
01248     // Finds NumEig largest eigen values
01249     TFltIntKdV sv(K);
01250     for (i = 0; i < K; i++) {
01251         sv[i].Key = TFlt::Abs(d[i+1]);
01252         sv[i].Dat = i;
01253     }
01254     sv.Sort(false);
01255 
01256     TFltV uu(Matrix.GetRows());
01257     const int FinalNumEig = TInt::GetMn(NumEig, K);
01258     EigValV.Reserve(FinalNumEig,0);
01259     EigVecVV.Gen(Matrix.GetCols(), FinalNumEig);
01260     for (i = 0; i < FinalNumEig; i++) {
01261         //printf("s[%d] = %20.15f\r", i, sv[i].Key.Val);
01262         int ii = sv[i].Dat;
01263         double sigma = d[ii+1].Val;
01264         // calculate singular value
01265         EigValV.Add(sigma);
01266         // calculate i-th right singular vector ( V := Q * W )
01267         TLinAlg::Multiply(Q, V, ii, EigVecVV, i);
01268     }
01269     //printf("done                           \n");
01270 }
01271 
01272 void TSparseSVD::Lanczos2(const TMatrix& Matrix, int MaxNumEig,
01273     int MaxSecs, const TSpSVDReOrtoType& ReOrtoType,
01274     TFltV& EigValV, TFltVV& EigVecVV, const bool& SvdMatrixProductP) {
01275 
01276   if (SvdMatrixProductP) {
01277     // if this fails, use transposed matrix
01278     IAssert(Matrix.GetRows() >= Matrix.GetCols());
01279   } else {
01280     IAssert(Matrix.GetRows() == Matrix.GetCols());
01281   }
01282   //IAssertR(NumEig <= Iters, TStr::Fmt("%d <= %d", NumEig, Iters));
01283 
01284   //if (ReOrtoType == ssotFull) printf("Full reortogonalization\n");
01285   int i, N = Matrix.GetCols(), K; // K - current dimension of T
01286   double t = 0.0, eps = 1e-6; // t - 1-norm of T
01287 
01288   //sequence of Ritz's vectors
01289   TFltVV Q(N, MaxNumEig);
01290   double tmp = 1/sqrt((double)N);
01291   for (i = 0; i < N; i++)
01292       Q(i,0) = tmp;
01293   //converget Ritz's vectors
01294   TVec<TFltV> ConvgQV(MaxNumEig);
01295   TIntV CountConvgV(MaxNumEig);
01296   for (i = 0; i < MaxNumEig; i++) CountConvgV[i] = 0;
01297   // const int ConvgTreshold = 50;
01298 
01299   //diagonal and subdiagonal of T
01300   TFltV d(MaxNumEig+1), e(MaxNumEig+1);
01301   //eigenvectors of T
01302   //TFltVV V;
01303   TFltVV V(MaxNumEig, MaxNumEig);
01304 
01305   // z - current Lanczos's vector
01306   TFltV z(N), bb(MaxNumEig), aa(MaxNumEig), y(N);
01307   //printf("svd(%d,%d)...\n", NumEig, Iters);
01308 
01309   if (SvdMatrixProductP) {
01310       // A = Matrix'*Matrix
01311       MultiplyATA(Matrix, Q, 0, z);
01312   } else {
01313       // A = Matrix
01314       Matrix.Multiply(Q, 0, z);
01315   }
01316   TExeTm ExeTm;
01317   for (int j = 0; j < (MaxNumEig-1); j++) {
01318     printf("%d [%s]..\r",j+2, ExeTm.GetStr());
01319     if (ExeTm.GetSecs() > MaxSecs) { break; }
01320 
01321     //calculates (j+1)-th Lanczos's vector
01322     // aa[j] = <Q(:,j), z>
01323     aa[j] = TLinAlg::DotProduct(Q, j, z);
01324     //printf(" %g -- ", aa[j].Val); //HACK
01325 
01326     TLinAlg::AddVec(-aa[j], Q, j, z);
01327     if (j > 0) {
01328         // z := -aa[j] * Q(:,j) + z
01329         TLinAlg::AddVec(-bb[j-1], Q, j-1, z);
01330 
01331         //reortogonalization
01332         if (ReOrtoType == ssotSelective || ReOrtoType == ssotFull) {
01333             for (i = 0; i <= j; i++) {
01334                 // if i-tj vector converget, than we have to ortogonalize against it
01335                 if ((ReOrtoType == ssotFull) ||
01336                     (bb[j-1] * TFlt::Abs(V(K-1, i)) < eps * t)) {
01337 
01338                     ConvgQV[i].Reserve(N,N); CountConvgV[i]++;
01339                     TFltV& vec = ConvgQV[i];
01340                     //vec = Q * V(:,i)
01341                     for (int k = 0; k < N; k++) {
01342                         vec[k] = 0.0;
01343                         for (int l = 0; l < K; l++)
01344                             vec[k] += Q(k,l) * V(l,i);
01345                     }
01346                     TLinAlg::AddVec(-TLinAlg::DotProduct(ConvgQV[i], z), ConvgQV[i], z ,z);
01347                 }
01348             }
01349         }
01350     }
01351 
01352     //adds (j+1)-th Lanczos's vector to Q
01353     bb[j] = TLinAlg::Norm(z);
01354     if (!(bb[j] > 1e-10)) {
01355       printf("Rank of matrix is only %d\n", j+2);
01356       printf("Last singular value is %g\n", bb[j].Val);
01357       break;
01358     }
01359     for (i = 0; i < N; i++)
01360         Q(i, j+1) = z[i] / bb[j];
01361 
01362     //next Lanzcos vector
01363     if (SvdMatrixProductP) {
01364         // A = Matrix'*Matrix
01365         MultiplyATA(Matrix, Q, j+1, z);
01366     } else {
01367         // A = Matrix
01368         Matrix.Multiply(Q, j+1, z);
01369     }
01370 
01371     //calculate T (K x K matrix)
01372     K = j + 2;
01373     // calculate diagonal
01374     for (i = 1; i < K; i++) d[i] = aa[i-1];
01375     d[K] = TLinAlg::DotProduct(Q, K-1, z);
01376     // calculate subdiagonal
01377     e[1] = 0.0;
01378     for (i = 2; i <= K; i++) e[i] = bb[i-2];
01379 
01380     //calculate 1-norm of T
01381     t = TFlt::GetMx(TFlt::Abs(d[1]) + TFlt::Abs(e[2]), TFlt::Abs(e[K]) + TFlt::Abs(d[K]));
01382     for (i = 2; i < K; i++)
01383         t = TFlt::GetMx(t, TFlt::Abs(e[i]) + TFlt::Abs(d[i]) + TFlt::Abs(e[i+1]));
01384 
01385     //set V to identity matrix
01386     //V.Gen(K,K);
01387     for (i = 0; i < K; i++) {
01388         for (int k = 0; k < K; k++)
01389             V(i,k) = 0.0;
01390         V(i,i) = 1.0;
01391     }
01392 
01393     //eigenvectors of T
01394     TNumericalStuff::EigSymmetricTridiag(d, e, K, V);
01395   }//for
01396   printf("... calc %d.", K);
01397   // Finds NumEig largest eigen values
01398   TFltIntKdV sv(K);
01399   for (i = 0; i < K; i++) {
01400     sv[i].Key = TFlt::Abs(d[i+1]);
01401     sv[i].Dat = i;
01402   }
01403   sv.Sort(false);
01404 
01405   TFltV uu(Matrix.GetRows());
01406   const int FinalNumEig = K; //TInt::GetMn(NumEig, K);
01407   EigValV.Reserve(FinalNumEig,0);
01408   EigVecVV.Gen(Matrix.GetCols(), FinalNumEig);
01409   for (i = 0; i < FinalNumEig; i++) {
01410     //printf("s[%d] = %20.15f\r", i, sv[i].Key.Val);
01411     int ii = sv[i].Dat;
01412     double sigma = d[ii+1].Val;
01413     // calculate singular value
01414     EigValV.Add(sigma);
01415     // calculate i-th right singular vector ( V := Q * W )
01416     TLinAlg::Multiply(Q, V, ii, EigVecVV, i);
01417   }
01418   printf("  done\n");
01419 }
01420 
01421 
01422 void TSparseSVD::SimpleLanczosSVD(const TMatrix& Matrix,
01423         const int& CalcSV, TFltV& SngValV, const bool& DoLocalReorto) {
01424 
01425     SimpleLanczos(Matrix, CalcSV, SngValV, DoLocalReorto, true);
01426     for (int SngValN = 0; SngValN < SngValV.Len(); SngValN++) {
01427       //IAssert(SngValV[SngValN] >= 0.0);
01428       if (SngValV[SngValN] < 0.0) {
01429         printf("bad sng val: %d %g\n", SngValN, SngValV[SngValN]());
01430         SngValV[SngValN] = 0;
01431       }
01432       SngValV[SngValN] = sqrt(SngValV[SngValN].Val);
01433     }
01434 }
01435 
01436 void TSparseSVD::LanczosSVD(const TMatrix& Matrix, int NumSV,
01437         int Iters, const TSpSVDReOrtoType& ReOrtoType,
01438         TFltV& SgnValV, TFltVV& LeftSgnVecVV, TFltVV& RightSgnVecVV) {
01439 
01440     // solve eigen problem for Matrix'*Matrix
01441     Lanczos(Matrix, NumSV, Iters, ReOrtoType, SgnValV, RightSgnVecVV, true);
01442     // calculate left singular vectors and sqrt singular values
01443     const int FinalNumSV = SgnValV.Len();
01444     LeftSgnVecVV.Gen(Matrix.GetRows(), FinalNumSV);
01445     TFltV LeftSgnVecV(Matrix.GetRows());
01446     for (int i = 0; i < FinalNumSV; i++) {
01447         if (SgnValV[i].Val < 0.0) { SgnValV[i] = 0.0; }
01448         const double SgnVal = sqrt(SgnValV[i]);
01449         SgnValV[i] = SgnVal;
01450         // calculate i-th left singular vector ( U := A * V * S^(-1) )
01451         Matrix.Multiply(RightSgnVecVV, i, LeftSgnVecV);
01452         for (int j = 0; j < LeftSgnVecV.Len(); j++) {
01453             LeftSgnVecVV(j,i) = LeftSgnVecV[j] / SgnVal; }
01454     }
01455     //printf("done                           \n");
01456 }
01457 
01458 void TSparseSVD::Project(const TIntFltKdV& Vec, const TFltVV& U, TFltV& ProjVec) {
01459     const int m = U.GetCols(); // number of columns
01460 
01461     ProjVec.Gen(m, 0);
01462     for (int j = 0; j < m; j++) {
01463         double x = 0.0;
01464         for (int i = 0; i < Vec.Len(); i++)
01465             x += U(Vec[i].Key, j) * Vec[i].Dat;
01466         ProjVec.Add(x);
01467     }
01468 }
01469 
01471 // Sigmoid
01472 double TSigmoid::EvaluateFit(const TFltIntKdV& data, const double A, const double B)
01473 {
01474   double J = 0.0;
01475   for (int i = 0; i < data.Len(); i++)
01476   {
01477     double zi = data[i].Key; int yi = data[i].Dat;
01478     double e = exp(-A * zi + B);
01479     double denum = 1.0 + e;
01480     double prob = (yi > 0) ? (1.0 / denum) : (e / denum);
01481     J -= log(prob < 1e-20 ? 1e-20 : prob);
01482   }
01483   return J;
01484 }
01485 
01486 void TSigmoid::EvaluateFit(const TFltIntKdV& data, const double A, const double B, double& J, double& JA, double& JB)
01487 {
01488   //               J(A, B) = \sum_{i : y_i = 1} ln [1 + e^{-Az_i + B}] + \sum_{i : y_i = -1} [ln [1 + e^{-Az_i + B}] - {-Az_i + B}]
01489   //                       = \sum_i ln [1 + e^{-Az_i + B}] - \sum_{i : y_i = -1} {-Az_i + B}.
01490   // partial J / partial A = \sum_i (-z_i) e^{-Az_i + B} / [1 + e^{-Az_i + B}] + \sum_{i : y_i = -1} Az_i.
01491   // partial J / partial B = \sum_i        e^{-Az_i + B} / [1 + e^{-Az_i + B}] + \sum_{i : y_i = -1} (-1).
01492   J = 0.0; double sum_all_PyNeg = 0.0, sum_all_ziPyNeg = 0.0, sum_yNeg_zi = 0.0, sum_yNeg_1 = 0.0;
01493   for (int i = 0; i < data.Len(); i++)
01494   {
01495     double zi = data[i].Key; int yi = data[i].Dat;
01496     double e = exp(-A * zi + B);
01497     double denum = 1.0 + e;
01498     double prob = (yi > 0) ? (1.0 / denum) : (e / denum);
01499     J -= log(prob < 1e-20 ? 1e-20 : prob);
01500     sum_all_PyNeg += e / denum;
01501     sum_all_ziPyNeg += zi * e / denum;
01502     if (yi < 0) { sum_yNeg_zi += zi; sum_yNeg_1 += 1; }
01503   }
01504   JA = -sum_all_ziPyNeg +     sum_yNeg_zi;
01505   JB =  sum_all_PyNeg   -     sum_yNeg_1;
01506 }
01507 
01508 void TSigmoid::EvaluateFit(const TFltIntKdV& data, const double A, const double B, const double U,
01509                            const double V, const double lambda, double& J, double& JJ, double& JJJ)
01510 {
01511   // Let E_i = e^{-(A + lambda U) z_i + (B + lambda V)}.  Then we have
01512   // J(lambda) = \sum_i ln [1 + E_i] - \sum_{i : y_i = -1} {-(A + lambda U)z_i + (B + lambda V)}.
01513   // J'(lambda) = \sum_i (V - U z_i) E_i / [1 + E_i] - \sum_{i : y_i = -1} {V - U z_i).
01514   //            = \sum_i (V - U z_i) [1 - 1 / [1 + E_i]] - \sum_{i : y_i = -1} {V - U z_i).
01515   // J"(lambda) = \sum_i (V - U z_i)^2 E_i / [1 + E_i]^2.
01516   J = 0.0; JJ = 0.0; JJJ = 0.0;
01517   for (int i = 0; i < data.Len(); i++)
01518   {
01519     double zi = data[i].Key; int yi = data[i].Dat;
01520     double e = exp(-A * zi + B);
01521     double denum = 1.0 + e;
01522     double prob = (yi > 0) ? (1.0 / denum) : (e / denum);
01523     J -= log(prob < 1e-20 ? 1e-20 : prob);
01524     double VU = V - U * zi;
01525     JJ += VU * (e / denum); if (yi < 0) JJ -= VU;
01526     JJJ += VU * VU * e / denum / denum;
01527   }
01528 }
01529 
01530 TSigmoid::TSigmoid(const TFltIntKdV& data) {
01531   // Let z_i be the projection of the i'th training example, and y_i \in {-1, +1} be its class label.
01532   // Our sigmoid is: P(Y = y | Z = z) = 1 / [1 + e^{-Az + B}]
01533   // and we want to maximize \prod_i P(Y = y_i | Z = z_i)
01534   //                       = \prod_{i : y_i = 1} 1 / [1 + e^{-Az_i + B}]  \prod_{i : y_i = -1} e^{-Az_i + B} / [1 + e^{-Az_i + B}]
01535   // or minimize its negative logarithm,
01536   //               J(A, B) = \sum_{i : y_i = 1} ln [1 + e^{-Az_i + B}] + \sum_{i : y_i = -1} [ln [1 + e^{-Az_i + B}] - {-Az_i + B}]
01537   //                       = \sum_i ln [1 + e^{-Az_i + B}] - \sum_{i : y_i = -1} {-Az_i + B}.
01538   // partial J / partial A = \sum_i (-z_i) e^{-Az_i + B} / [1 + e^{-Az_i + B}] + \sum_{i : y_i = -1} Az_i.
01539   // partial J / partial B = \sum_i        e^{-Az_i + B} / [1 + e^{-Az_i + B}] + \sum_{i : y_i = -1} (-1).
01540   double minProj = data[0].Key, maxProj = data[0].Key;
01541   {for (int i = 1; i < data.Len(); i++) {
01542     double zi = data[i].Key; if (zi < minProj) minProj = zi; if (zi > maxProj) maxProj = zi; }}
01543   //const bool dump = false;
01544   A = 1.0; B = 0.5 * (minProj + maxProj);
01545   double bestJ = 0.0, bestA = 0.0, bestB = 0.0, lambda = 1.0;
01546   for (int nIter = 0; nIter < 50; nIter++)
01547   {
01548     double J, JA, JB; TSigmoid::EvaluateFit(data, A, B, J, JA, JB);
01549     if (nIter == 0 || J < bestJ) { bestJ = J; bestA = A; bestB = B; }
01550     // How far should we move?
01551     //if (dump) printf("Iter %2d: A = %.5f, B = %.5f, J = %.5f, partial = (%.5f, %.5f)\n", nIter, A, B, J, JA, JB);
01552         double norm = TMath::Sqr(JA) + TMath::Sqr(JB);
01553     if (norm < 1e-10) break;
01554     const int cl = -1; // should be -1
01555 
01556     double Jc = TSigmoid::EvaluateFit(data, A + cl * lambda * JA / norm, B + cl * lambda * JB / norm);
01557     //if (dump) printf("  At lambda = %.5f, Jc = %.5f\n", lambda, Jc);
01558     if (Jc > J) {
01559       while (lambda > 1e-5) {
01560         lambda = 0.5 * lambda;
01561         Jc = TSigmoid::EvaluateFit(data, A + cl * lambda * JA / norm, B + cl * lambda * JB / norm);
01562         //if (dump) printf("  At lambda = %.5f, Jc = %.5f\n", lambda, Jc);
01563       } }
01564     else if (Jc < J) {
01565       while (lambda < 1e5) {
01566         double lambda2 = 2 * lambda;
01567         double Jc2 = TSigmoid::EvaluateFit(data, A + cl * lambda2 * JA / norm, B + cl * lambda2 * JB / norm);
01568         //if (dump) printf("  At lambda = %.5f, Jc = %.5f\n", lambda2, Jc2);
01569         if (Jc2 > Jc) break;
01570         lambda = lambda2; Jc = Jc2; } }
01571     if (Jc >= J) break;
01572     A += cl * lambda * JA / norm; B += cl * lambda * JB / norm;
01573     //if (dump) printf("   Lambda = %.5f, new A = %.5f, new B = %.5f, new J = %.5f\n", lambda, A, B, Jc);
01574   }
01575   A = bestA; B = bestB;
01576 }
01577 
01579 // Useful stuff (hopefuly)
01580 void TLAMisc::SaveCsvTFltV(const TFltV& Vec, TSOut& SOut) {
01581     for (int ValN = 0; ValN < Vec.Len(); ValN++) {
01582         SOut.PutFlt(Vec[ValN]); SOut.PutCh(',');
01583     }
01584     SOut.PutLn();
01585 }
01586 
01587 void TLAMisc::SaveMatlabTFltIntKdV(const TIntFltKdV& SpV, const int& ColN, TSOut& SOut) {
01588     const int Len = SpV.Len();
01589     for (int ValN = 0; ValN < Len; ValN++) {
01590         SOut.PutStrLn(TStr::Fmt("%d %d %g", SpV[ValN].Key+1, ColN+1, SpV[ValN].Dat()));
01591     }
01592 }
01593 
01594 void TLAMisc::SaveMatlabTFltV(const TFltV& m, const TStr& FName) {
01595     PSOut out = TFOut::New(FName);
01596     const int RowN = m.Len();
01597     for (int RowId = 0; RowId < RowN; RowId++) {
01598         out->PutStr(TFlt::GetStr(m[RowId], 20, 18));
01599         out->PutCh('\n');
01600     }
01601     out->Flush();
01602 }
01603 
01604 void TLAMisc::SaveMatlabTIntV(const TIntV& m, const TStr& FName) {
01605     PSOut out = TFOut::New(FName);
01606     const int RowN = m.Len();
01607     for (int RowId = 0; RowId < RowN; RowId++) {
01608         out->PutInt(m[RowId]);
01609         out->PutCh('\n');
01610     }
01611     out->Flush();
01612 }
01613 
01614 void TLAMisc::SaveMatlabTFltVVCol(const TFltVV& m, int ColId, const TStr& FName) {
01615     PSOut out = TFOut::New(FName);
01616     const int RowN = m.GetRows();
01617     for (int RowId = 0; RowId < RowN; RowId++) {
01618         out->PutStr(TFlt::GetStr(m(RowId,ColId), 20, 18));
01619         out->PutCh('\n');
01620     }
01621     out->Flush();
01622 }
01623 
01624 
01625 void TLAMisc::SaveMatlabTFltVV(const TFltVV& m, const TStr& FName) {
01626     PSOut out = TFOut::New(FName);
01627     const int RowN = m.GetRows();
01628     const int ColN = m.GetCols();
01629     for (int RowId = 0; RowId < RowN; RowId++) {
01630         for (int ColId = 0; ColId < ColN; ColId++) {
01631             out->PutStr(TFlt::GetStr(m(RowId,ColId), 20, 18));
01632             out->PutCh(' ');
01633         }
01634         out->PutCh('\n');
01635     }
01636     out->Flush();
01637 }
01638 
01639 void TLAMisc::SaveMatlabTFltVVMjrSubMtrx(const TFltVV& m,
01640         int RowN, int ColN, const TStr& FName) {
01641 
01642     PSOut out = TFOut::New(FName);
01643     for (int RowId = 0; RowId < RowN; RowId++) {
01644         for (int ColId = 0; ColId < ColN; ColId++) {
01645             out->PutStr(TFlt::GetStr(m(RowId,ColId), 20, 18)); out->PutCh(' ');
01646         }
01647         out->PutCh('\n');
01648     }
01649     out->Flush();
01650 }
01651 
01652 void TLAMisc::LoadMatlabTFltVV(const TStr& FNm, TVec<TFltV>& ColV) {
01653     PSIn SIn = TFIn::New(FNm);
01654     TILx Lx(SIn, TFSet()|iloRetEoln|iloSigNum|iloExcept);
01655     int Row = 0, Col = 0; ColV.Clr();
01656     Lx.GetSym(syFlt, syEof, syEoln);
01657     //printf("%d x %d\r", Row, ColV.Len());
01658     while (Lx.Sym != syEof) {
01659         if (Lx.Sym == syFlt) {
01660             if (ColV.Len() > Col) {
01661                 IAssert(ColV[Col].Len() == Row);
01662                 ColV[Col].Add(Lx.Flt);
01663             } else {
01664                 IAssert(Row == 0);
01665                 ColV.Add(TFltV::GetV(Lx.Flt));
01666             }
01667             Col++;
01668         } else if (Lx.Sym == syEoln) {
01669             IAssert(Col == ColV.Len());
01670             Col = 0; Row++;
01671             if (Row%100 == 0) {
01672                 //printf("%d x %d\r", Row, ColV.Len());
01673             }
01674         } else {
01675             Fail;
01676         }
01677         Lx.GetSym(syFlt, syEof, syEoln);
01678     }
01679     //printf("\n");
01680     IAssert(Col == ColV.Len() || Col == 0);
01681 }
01682 
01683 void TLAMisc::LoadMatlabTFltVV(const TStr& FNm, TFltVV& MatrixVV) {
01684     TVec<TFltV> ColV; LoadMatlabTFltVV(FNm, ColV);
01685     if (ColV.Empty()) { MatrixVV.Clr(); return; }
01686     const int Rows = ColV[0].Len(), Cols = ColV.Len();
01687     MatrixVV.Gen(Rows, Cols);
01688     for (int RowN = 0; RowN < Rows; RowN++) {
01689         for (int ColN = 0; ColN < Cols; ColN++) {
01690             MatrixVV(RowN, ColN) = ColV[ColN][RowN];
01691         }
01692     }
01693 }
01694 
01695 
01696 void TLAMisc::PrintTFltV(const TFltV& Vec, const TStr& VecNm) {
01697     printf("%s = [", VecNm.CStr());
01698     for (int i = 0; i < Vec.Len(); i++) {
01699         printf("%.5f", Vec[i]());
01700                 if (i < Vec.Len() - 1) { printf(", "); }
01701     }
01702     printf("]\n");
01703 }
01704 
01705 
01706 void TLAMisc::PrintTFltVV(const TFltVV& A, const TStr& MatrixNm) {
01707     printf("%s = [\n", MatrixNm.CStr());
01708         for (int j = 0; j < A.GetRows(); j++) {
01709                 for (int i = 0; i < A.GetCols(); i++) {
01710                         printf("%f\t", A.At(i, j).Val);
01711                 }
01712                 printf("\n");
01713         }
01714     printf("]\n");
01715 }
01716 
01717 void TLAMisc::PrintTIntV(const TIntV& Vec, const TStr& VecNm) {
01718     printf("%s = [", VecNm.CStr());
01719     for (int i = 0; i < Vec.Len(); i++) {
01720         printf("%d", Vec[i]());
01721         if (i < Vec.Len() - 1) printf(", ");
01722     }
01723     printf("]\n");
01724 }
01725 
01726 
01727 void TLAMisc::FillRnd(TFltV& Vec, TRnd& Rnd) {
01728     int Len = Vec.Len();
01729     for (int i = 0; i < Len; i++)
01730         Vec[i] = Rnd.GetNrmDev();
01731 }
01732 
01733 void TLAMisc::FillIdentity(TFltVV& M) {
01734     IAssert(M.GetRows() == M.GetCols());
01735     int Len = M.GetRows();
01736     for (int i = 0; i < Len; i++) {
01737         for (int j = 0; j < Len; j++) M(i,j) = 0.0;
01738         M(i,i) = 1.0;
01739     }
01740 }
01741 
01742 void TLAMisc::FillIdentity(TFltVV& M, const double& Elt) {
01743     IAssert(M.GetRows() == M.GetCols());
01744     int Len = M.GetRows();
01745     for (int i = 0; i < Len; i++) {
01746         for (int j = 0; j < Len; j++) M(i,j) = 0.0;
01747         M(i,i) = Elt;
01748     }
01749 }
01750 
01751 int TLAMisc::SumVec(const TIntV& Vec) {
01752     const int Len = Vec.Len();
01753     int res = 0;
01754     for (int i = 0; i < Len; i++)
01755         res += Vec[i];
01756     return res;
01757 }
01758 
01759 double TLAMisc::SumVec(const TFltV& Vec) {
01760     const int Len = Vec.Len();
01761     double res = 0.0;
01762     for (int i = 0; i < Len; i++)
01763         res += Vec[i];
01764     return res;
01765 }
01766 
01767 void TLAMisc::ToSpVec(const TFltV& Vec, TIntFltKdV& SpVec,
01768         const double& CutSumPrc) {
01769 
01770     // determine minimal element value
01771     IAssert(0.0 <= CutSumPrc && CutSumPrc <= 1.0);
01772     const int Elts = Vec.Len();
01773     double EltSum = 0.0;
01774     for (int EltN = 0; EltN < Elts; EltN++) {
01775         EltSum += TFlt::Abs(Vec[EltN]); }
01776     const double MnEltVal = CutSumPrc * EltSum;
01777     // create sparse vector
01778     SpVec.Clr();
01779     for (int EltN = 0; EltN < Elts; EltN++) {
01780         if (TFlt::Abs(Vec[EltN]) > MnEltVal) {
01781             SpVec.Add(TIntFltKd(EltN, Vec[EltN]));
01782         }
01783     }
01784     SpVec.Pack();
01785 }
01786 
01787 void TLAMisc::ToVec(const TIntFltKdV& SpVec, TFltV& Vec, const int& VecLen) {
01788     Vec.Gen(VecLen); Vec.PutAll(0.0);
01789     int Elts = SpVec.Len();
01790     for (int EltN = 0; EltN < Elts; EltN++) {
01791         if (SpVec[EltN].Key < VecLen) {
01792             Vec[SpVec[EltN].Key] = SpVec[EltN].Dat;
01793         }
01794     }
01795 }