CEBL  2.1
IncrementalSVD.cpp
Go to the documentation of this file.
1 #include "IncrementalSVD.hpp"
2 using namespace cppR;
3 
4 typedef ublas::matrix<double> Matrix;
5 typedef ublas::vector<double> Vector;
6 namespace CEBL
7 {
8  //default constructor
9  IncrementalSVD::IncrementalSVD()
10  {
11  n_lags = 0;
12  bufferEmpty = true;
13  svd_state_set = false;
14  lambda = 0.99;
15  plugin_name = "Incremental SVD";
16  }
17 
18 
20  std::map<std::string, CEBL::Param> IncrementalSVD::getParamsList()
21  {
22  std::map<std::string, CEBL::Param> params;
23  CEBL::Param lags("Lags", "How many lags?", n_lags);
24  lags.setMax(500);
25  lags.setMin(0);
26  params["lags"] = lags;
27 
28  CEBL::Param lambda_param("Lambda", "", lambda);
29  lambda_param.setStep(0.001);
30  lambda_param.setMax(1.0);
31  lambda_param.setMin(0.0);
32 
33  params["lambda"] = lambda_param;
34 
35  return params;
36  }
37 
38 
40  void IncrementalSVD::setParamsList( std::map<std::string, CEBL::Param> &params)
41  {
42  std::map<std::string, CEBL::Param> p = params;
43  int new_lags = p["lags"].getInt();
44  if(new_lags != n_lags)
45  {
46  n_lags = new_lags;
47  reset();
48  }
49 
50  lambda = p["lambda"].getDouble();
51  }
52 
53 
55  Matrix IncrementalSVD::use(const Matrix &data)
56  {
57  should_halt = false;
58 
59  //lagged data
60  Matrix lagged_data;
61 
62  if (n_lags > 0)
63  {
64  if (bufferEmpty)
65  {
66  buffer = data;
67  bufferEmpty = false;
68  }
69  else
70  {
71  // cbind (concatentate) new data onto right side of buffer
72  int nRowsBuffer = nrow(buffer);
73  int nColsBuffer = ncol(buffer);
74  int nColsData = ncol(data);
75  Matrix keep =
76  submatrix(buffer,0,nRowsBuffer-1,
77  nColsBuffer-n_lags, nColsBuffer-1);
78  buffer = keep;
79  buffer.resize(nRowsBuffer, n_lags+nColsData);
80  nColsBuffer = ncol(buffer);
81  submatrix(buffer, 0, nRowsBuffer-1,
82  nColsBuffer-nColsData, nColsBuffer-1) = data;
83  }
84 
85  // will produce error if n_lags >= ncol(buffer)
86  this->inturruptionPoint();
87  lagged_data = cppR::Lag(buffer,n_lags);
88  }
89  else
90  {
91  // n_lags == 0
92  lagged_data = data;
93  }
94 
95  //svd the lagged data;
96  this->inturruptionPoint();
97  Matrix svdized_data = ISVD(lagged_data);
98 
99  //write stuff to an R file
100  /*r_writer.Add(data,"data");
101  r_writer.Add(lagged_data,"lagged.data");
102  r_writer.Add(svdized_data,"svdized.data");
103  r_writer.Write("temp.R");*/
104  return svdized_data;
105 
106  }
107 
108 
109  map<string, SerializedObject> IncrementalSVD::save() const
110  {
111  map<string, SerializedObject> ret;
112  ret["n_lags"] = serialize(n_lags);
113  ret["lambda"] = serialize(lambda);
114 
115  return ret;
116  }
117  void IncrementalSVD::load(map<string, SerializedObject> objects)
118  {
119  deserialize(objects["n_lags"],n_lags);
120  deserialize(objects["lambda"],lambda);
121  }
122 
123 
125  void IncrementalSVD::reset()
126  {
127  buffer.resize(0,0);
128  bufferEmpty = true;
129  svd_state_set = false;
130  cout << "reset called\n";
131  }
132 
133 
134  /**************************************************/
135 
136 
137  Matrix IncrementalSVD::ISVD(Matrix data)
138  {
139  //make sure matrix dimensions are okay
140  if(svd_state_set && nrow(data)!=ncol(svd_state.U))
141  {
142  svd_state_set = false;
143  }
144  //create state variables
145  if(!svd_state_set)
146  {
147  svd_state.U = diag(1,nrow(data));
148  svd_state.s = createVector(0.1,nrow(data));
149  svd_state_set = true;
150  }
151  //do the incremental svd
152  Matrix features;
153  features.resize(0,0);
154  for(int i=0; i < ncol(data); i++)
155  {
156  this->inturruptionPoint();
157  Matrix data_col = createMatrix(Vector(column(data,i)),0,1);
158  svd_state = SVDUpdateRank(data_col, svd_state,lambda);
159  Matrix U = createMatrix(createVector(svd_state.U),svd_state.U.size1()*svd_state.U.size2(),0);
160  if(features.size1() == 0)
161  features = U;
162  else
163  features = cbind(features,U);
164  }
165 
166  return features;
167  }
168 
169  //incremental svd function
170  SVDState IncrementalSVD::SVDUpdateRank(Matrix sample, SVDState state, double lambda)
171  {
172  int dimen = ncol(state.U);
173  if(state.s.size() < unsigned(dimen))
174  dimen = state.s.size();
175  //resize U and s
176  state.U.resize(state.U.size1(),dimen);
177  state.s.resize(dimen);
178 
179 
180 
181  Matrix m = prod(t(state.U),sample);
182  Matrix p = sample - prod(state.U, m);
183 
184  double pnorm = sqrt(sum(apply(p,pow,2)));
185 
186  Matrix sdiag = diag(state.s);
187 
188  Matrix K;
189  K.resize(nrow(m) + 1, ncol(sdiag) + ncol(m));
190 
191 
192  //create K matrix
193  submatrix(K,0,nrow(m)-1,0,0) = Matrix(cbind(sdiag,m));
194  int last_row = nrow(K)-1;
195  for(int i=0;i<ncol(K);i++)
196  {
197  this->inturruptionPoint();
198  if(i < dimen)
199  K(last_row,i) = 0;
200  else
201  K(last_row,i) = pnorm;
202  }
203  //run svd
204  SvdStruct<double> r = svd(K);
205  Matrix Up = r.u;
206  Vector sp = r.d;
207 
208  Matrix P;
209  if(pnorm==0)
210  P = p * 0;
211  else
212  P = p * (1.0/pnorm);
213 
214 
215  state.U = prod(cbind(state.U,P),Up);
216  state.U.resize(state.U.size1(),dimen);
217 
218 
219  //reverse direction of negative singular vectors
220 
221  for(int col=0;col<ncol(state.U);col++)
222  {
223  this->inturruptionPoint();
224  bool s = state.U(0,col) < 0;
225  for(int row=0;row<nrow(state.U);row++)
226  if(s)
227  state.U(row,col) = -state.U(row,col);
228  }
229 
230  sp.resize(dimen);
231  state.s = sp * lambda;
232 
233  return state;
234  }
235 
236 }
237 
238 /*************************************************************/
239 //DYNAMIC LOADING
240 
242 {
243  return new CEBL::IncrementalSVD;
244 }
245 
246 extern "C" void ObjectDestroy(CEBL::Feature* p)
247 {
248  delete p;
249 }