4
#include "incomplete_qr.h"
6
/* The MATLAB code for this algorithm:
9
for j=find(Rpattern(1:i-1,i))'
14
q=q.*(abs(q)>Qdroptol*R(i,i));
15
Q(:,i)=q/(norm(q)+1e-300);
19
static inline double sqr(double x)
30
SparseEntry(int index_, double value_) : index(index_), value(value_) {}
31
bool operator<(const SparseEntry &e) const { return index<e.index; }
34
typedef std::list<SparseEntry> DynamicSparseVector;
35
typedef std::vector<SparseEntry> StaticSparseVector;
37
static void copy_column(int colstart, int nextcolstart, const int *rowindex, const double *value,
38
DynamicSparseVector &v)
40
for(int i=colstart; i<nextcolstart; ++i)
41
v.push_back(SparseEntry(rowindex[i], value[i]));
44
static double dot_product(const StaticSparseVector &u, const DynamicSparseVector &v)
46
StaticSparseVector::const_iterator p=u.begin();
47
if(p==u.end()) return 0;
48
DynamicSparseVector::const_iterator q=v.begin();
49
if(q==v.end()) return 0;
52
if(p->index < q->index){
53
++p; if(p==u.end()) break;
54
}else if(p->index > q->index){
55
++q; if(q==v.end()) break;
56
}else{ // p->index == q->index
57
result+=p->value*q->value;
58
++p; if(p==u.end()) break;
59
++q; if(q==v.end()) break;
65
static void add_to_vector(double multiplier, const StaticSparseVector &u, DynamicSparseVector &v)
67
StaticSparseVector::const_iterator p=u.begin();
68
if(p==u.end()) return;
69
DynamicSparseVector::iterator q=v.begin();
72
if(p->index < q->index){
73
q=v.insert(q, SparseEntry(p->index, multiplier*p->value));
74
++p; if(p==u.end()) return;
75
}else if(p->index > q->index){
76
++q; if(q==v.end()) break;
77
}else{ // p->index == q->index){
78
q->value+=multiplier*p->value;
79
++p; if(p==u.end()) return;
80
++q; if(q==v.end()) break;
84
v.push_back(SparseEntry(p->index, multiplier*p->value));
85
++p; if(p==u.end()) return;
89
static double vector_norm(const DynamicSparseVector &v)
91
double norm_squared=0;
92
DynamicSparseVector::const_iterator p;
93
for(p=v.begin(); p!=v.end(); ++p) norm_squared+=sqr(p->value);
94
return std::sqrt(norm_squared);
97
static void copy_large_entries(const DynamicSparseVector &u, double threshhold, StaticSparseVector &v)
99
DynamicSparseVector::const_iterator p;
100
for(p=u.begin(); p!=u.end(); ++p){
101
if(std::fabs(p->value)>threshhold) v.push_back(*p);
105
static void normalize(StaticSparseVector &v)
107
double norm_squared=0;
108
StaticSparseVector::iterator p;
109
for(p=v.begin(); p!=v.end(); ++p) norm_squared+=sqr(p->value);
111
double scale=1/std::sqrt(norm_squared);
112
for(p=v.begin(); p!=v.end(); ++p) p->value*=scale;
116
void incomplete_qr(int m, int n, const int *Acolstart, const int *Arowindex, const double *Avalue,
118
const int *Rcolstart, const int *Rrowindex, double *Rvalue, double *Rdiag)
120
// column storage for intermediate Q
121
std::vector<StaticSparseVector> Q(n);
123
// for each column of Q, how many more times it will be used in making R
124
// (once this gets decremented to zero, we can free the column)
125
std::vector<int> dependency_count(n,0);
126
for(int i=0; i<n; ++i){
127
for(int a=Rcolstart[i]; a<Rcolstart[i+1]; ++a){
129
if(j<i) ++dependency_count[j];
133
// construct R a column at a time
134
for(int i=0; i<n; ++i){
135
DynamicSparseVector q;
136
copy_column(Acolstart[i], Acolstart[i+1], Arowindex, Avalue, q);
137
for(int a=Rcolstart[i]; a<Rcolstart[i+1]; ++a){
140
Rvalue[a]=dot_product(Q[j], q);
141
add_to_vector(-Rvalue[a], Q[j], q);
142
--dependency_count[j];
143
if(dependency_count[j]==0) Q[j].clear();
145
Rvalue[a]=0; // ideally structure of R is upper triangular, so this waste of space won't happen
147
Rdiag[i]=vector_norm(q);
148
copy_large_entries(q, Qdroptol*Rdiag[i], Q[i]);