00001 #include "cross.hpp"
00002 #include <math.h>
00003
00004 Cross::Cross(const Matrix &M)
00005 : Skeleton(0), A(M), U(M.GetNumRows(), rank),
00006 V(M.GetNumCols(), rank), fnorm2(0)
00007 { }
00008
00009 Cross::~Cross() { }
00010
00011 const Matrix& Cross::GetM() const
00012 {
00013 return A;
00014 }
00015
00016 const Matrix& Cross::GetU() const
00017 {
00018 return U;
00019 }
00020
00021 const Matrix& Cross::GetV() const
00022 {
00023 return V;
00024 }
00025
00026 unsigned Cross::GetNumRows() const
00027 {
00028 return A.GetNumRows();
00029 }
00030
00031 unsigned Cross::GetNumCols() const
00032 {
00033
00034 return A.GetNumCols();
00035 }
00036
00037 double Cross::GetEps() const
00038 {
00039 return eps;
00040 }
00041
00042 double Cross::elem(unsigned i, unsigned j) const
00043 {
00044 unsigned k;
00045 double res = 0;
00046 #if HANDLEXCEPTION
00047 if((i < GetNumRows()) && (j < GetNumCols()))
00048 throw "assume i < num_rows and j < num_cols";
00049 }
00050 #endif
00051
00052 for(k = 0; k < rank; ++k) {
00053 res += U.elem(i, k) * V.elem(j, k);
00054 }
00055 return res;
00056 }
00057
00058
00059
00060
00061 static unsigned
00062 argmax_ignore_idx(const Vector& vec, const IndexList& ignore_idx)
00063 {
00064 unsigned res, i, j, size;
00065 double tmp, max_a = 0;
00066 size = ignore_idx.GetCurrentSize();
00067 i = ignore_idx.GetFirstNotListed();
00068 res = i;
00069 for(j = i; j < size; ++j) {
00070 for(; i < ignore_idx[j]; ++i) {
00071 tmp = fabs(vec.elem(i));
00072 if(tmp > max_a) {
00073 max_a = tmp;
00074 res = i;
00075 }
00076 }
00077 i = ignore_idx[j] + 1;
00078 }
00079 return res;
00080 }
00081
00082
00083
00084 void Cross::RecalcFnorm()
00085 {
00086 unsigned i, k, num_cols, num_rows;
00087 double tmp1, tmp2;
00088 num_cols = GetNumCols();
00089 num_rows = GetNumRows();
00090
00091 for(k = 0; k + 1 < rank; ++k) {
00092 for(tmp1 = 0, i = 0; i < num_rows; ++i) {
00093 tmp1 += U.elem(i, k) * U.elem(i, rank - 1);
00094 }
00095 for(tmp2 = 0, i = 0; i < num_cols; ++i) {
00096 tmp2 += V.elem(i, k) * V.elem(i, rank - 1);
00097 }
00098 fnorm2 += 2 * tmp1 * tmp2;
00099 }
00100 for(tmp1 = 0, i = 0; i < num_rows; ++i) {
00101 tmp1 += U.elem(i, rank - 1) * U.elem(i, rank - 1);
00102 }
00103 for(tmp2 = 0, i = 0; i < num_cols; ++i) {
00104 tmp2 += V.elem(i, rank - 1) * V.elem(i, rank - 1);
00105 }
00106
00107 fnorm2 += tmp1 * tmp2;
00108 }
00109
00110 void Cross::Approximate(double _eps)
00111 {
00112 unsigned i, j, t, num_cols, num_rows;
00113 double tmp;
00114 MatrixSub M(A, *this);
00115 num_cols = GetNumCols();
00116 num_rows = GetNumRows();
00117 eps = _eps;
00118 row_marked_index.AddIndex(num_rows);
00119 col_marked_index.AddIndex(num_cols);
00120 for(;;) {
00121
00122 i = argmax_ignore_idx(
00123 M.GetCol(col_marked_index.GetFirstNotListed()),
00124 row_marked_index
00125 );
00126 j = argmax_ignore_idx(M.GetRow(i), col_marked_index);
00127
00128
00129 tmp = M.elem(i, j);
00130 if(fabs(tmp) *
00131 sqrt((num_rows - (rank + 1)) * (num_cols - (rank + 1))) <=
00132 eps * sqrt(fnorm2))
00133 {
00134 break;
00135 }
00136
00137
00138 U.Resize(rank + 1);
00139 for(t = 0; t < num_rows; ++t) {
00140 U.elem(t, rank) = (M.elem(t, j)) / sqrt(fabs(tmp));
00141 }
00142 V.Resize(rank + 1);
00143 for(t = 0; t < num_cols; ++t) {
00144 V.elem(t, rank) = (M.elem(i, t)) * sqrt(fabs(tmp)) / tmp;
00145 }
00146
00147
00148 rank++;
00149
00150
00151 RecalcFnorm();
00152
00153
00154 row_marked_index.AddIndex(i);
00155 col_marked_index.AddIndex(j);
00156 }
00157 }
00158