00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00039 #include "quicsvd.h"
00040 #include <cmath>
00041
00042 QuicSVD::QuicSVD(const Matrix& A, double targetRelErr) : root_(A) {
00043 A_.Alias(A);
00044
00045 basis_.Init();
00046 UTA_.Init();
00047 projMagSq_.InitRepeat(0, n_cols());
00048 sumProjMagSq_ = 0;
00049 targetRelErr_ = targetRelErr;
00050 dataNorm2_ = root_.getSumL2();
00051
00052 }
00053
00054
00055
00056 bool MGS(const ArrayList<Vector>& basis, const Vector& newVec,
00057 Vector* newBasisVec) {
00058
00059
00060 newBasisVec->Copy(newVec);
00061 for (index_t i = 0; i < basis.size(); i++) {
00062 double prod = - la::Dot(basis[i], *newBasisVec);
00063 la::AddExpert(prod, basis[i], newBasisVec);
00064 }
00065
00066
00067
00068
00069 double L2 = la::LengthEuclidean(*newBasisVec);
00070 if (L2 > 1e-12) {
00071 la::Scale(1.0/L2, newBasisVec);
00072 return true;
00073 }
00074 else
00075 return false;
00076 }
00077
00078 void QuicSVD::addBasisFrom(const CosineNode& node) {
00079 Vector nodeBasis;
00080
00081 if (MGS(basis_, node.getMean(), &nodeBasis)) {
00082 Vector av;
00083 basis_.PushBackCopy(nodeBasis);
00084 la::MulInit(nodeBasis, A_, &av);
00085 UTA_.PushBackCopy(av);
00086 for (index_t i_col = 0; i_col < n_cols(); i_col++) {
00087 double magSq = math::Sqr(av[i_col]);
00088 projMagSq_[i_col] += magSq;
00089 sumProjMagSq_ += magSq;
00090 }
00091 }
00092 }
00093
00094
00095 double QuicSVD::curRelErr() {
00096 return sqrt((dataNorm2_ - sumProjMagSq_) / dataNorm2_);
00097 }
00098
00099
00100
00101 void QuicSVD::addToQueue(CosineNode* node) {
00102 if (node == NULL) return;
00103 node->setL2Err(calL2Err(*node));
00104 leaves_.push(node);
00105 }
00106
00107
00108
00109 double QuicSVD::calL2Err(const CosineNode& node) {
00110 double nodeSumL2 = node.getSumL2();
00111 double nodeSumProjL2 = 0;
00112 for (index_t i_col = 0; i_col < node.n_cols(); i_col++)
00113 nodeSumProjL2 += projMagSq_[node.getOrigIndex(i_col)];
00114 return nodeSumL2 - nodeSumProjL2;
00115 }
00116
00117
00118
00119
00120 void QuicSVD::ComputeSVD(Vector* s, Matrix* U, Matrix* VT) {
00121 leaves_.push(&root_);
00122 addBasisFrom(root_);
00123
00124
00125
00126
00127 while (curRelErr() > targetRelErr_) {
00128 CosineNode* node = leaves_.top();
00129 leaves_.pop();
00130
00131 node->Split();
00132
00133
00134
00135 if (node->hasRight()) addBasisFrom(*(node->getRight()));
00136
00137
00138 addToQueue(node->getLeft());
00139 addToQueue(node->getRight());
00140
00141
00142 }
00143
00144
00145
00146 extractSVD(s, U, VT);
00147 }
00148
00149
00150
00151
00152
00153
00154 void createUTA2(const ArrayList<Vector>& UTA, Matrix* UTA2) {
00155 UTA2->Init(UTA.size(), UTA.size());
00156 for (int i = 0; i < UTA.size(); i++)
00157 for (int j = 0; j < UTA.size(); j++)
00158 UTA2->ref(i, j) = la::Dot(UTA[i], UTA[j]);
00159 }
00160
00161
00162
00163 void MulInit(const ArrayList<Vector>& A, const Matrix& B,
00164 Matrix* C) {
00165 index_t m = A[0].length();
00166 index_t n = A.size();
00167 index_t p = B.n_cols();
00168 C->Init(m, p);
00169 for (index_t i = 0; i < m; i++)
00170 for (index_t j = 0; j < p; j++) {
00171 C->ref(i, j) = 0;
00172 for (index_t k = 0; k < n; k++)
00173 C->ref(i, j) += A[k][i] * B.get(k, j);
00174 }
00175 }
00176
00177
00178 void MulTransCInit(const ArrayList<Vector>& A, const Matrix& B,
00179 Matrix* C) {
00180 index_t m = A[0].length();
00181 index_t n = A.size();
00182 index_t p = B.n_cols();
00183 C->Init(p, m);
00184 for (index_t i = 0; i < m; i++)
00185 for (index_t j = 0; j < p; j++) {
00186 C->ref(j, i) = 0;
00187 for (index_t k = 0; k < n; k++)
00188 C->ref(j, i) += A[k][i] * B.get(k, j);
00189 }
00190 }
00191
00192
00193 void InverseRowScale(const Vector& s, Matrix* A) {
00194 for (index_t i = 0; i < A->n_rows(); i++)
00195 for (index_t j = 0; j < A->n_cols(); j++)
00196 A->ref(i, j) /= s[i];
00197 }
00198
00199
00200
00201 void QuicSVD::extractSVD(Vector* s, Matrix* U, Matrix* VT) {
00202
00203
00204 Matrix UTA2;
00205 Matrix Uprime, VprimeT;
00206 Vector sprime;
00207
00208
00209
00210 createUTA2(UTA_, &UTA2);
00211
00212 la::SVDInit(UTA2, &sprime, &Uprime, &VprimeT);
00213
00214 s->Init(sprime.length());
00215 for (index_t i = 0; i < sprime.length(); i++)
00216 (*s)[i] = sqrt(sprime[i]);
00217
00218
00219 MulInit(basis_, Uprime, U);
00220 MulTransCInit(UTA_, Uprime, VT);
00221 InverseRowScale(*s, VT);
00222
00223
00224
00225
00226 }
00227
00228
00229
00230
00231 double QuicSVD::SVDInit(const Matrix& A, double targetRelErr,
00232 Vector* s, Matrix* U, Matrix* VT) {
00233
00234 bool transpose = A.n_rows() > A.n_cols() * 1.1;
00235
00236 if (!transpose) {
00237 QuicSVD svd(A, targetRelErr);
00238 svd.ComputeSVD(s, U, VT);
00239 return svd.curRelErr();
00240 }
00241 else {
00242 Matrix AT, UT, V;
00243 la::TransposeInit(A, &AT);
00244 QuicSVD svd(AT, targetRelErr);
00245 svd.ComputeSVD(s, &V, &UT);
00246 la::TransposeInit(UT, U);
00247 la::TransposeInit(V, VT);
00248 return svd.curRelErr();
00249 }
00250 }