libROM  v1.0
Data-driven physical simulation library
IncrementalSVDStandard.cpp
1 
11 // Description: The concrete implementation of the incremental SVD algorithm
12 // that is equivalent to but computationally more expensive than
13 // the "fast update" method.
14 
15 #include "IncrementalSVDStandard.h"
16 #include "utils/HDFDatabase.h"
17 
18 #include "mpi.h"
19 
20 #include <cmath>
21 #include <limits>
22 
23 namespace CAROM {
24 
25 IncrementalSVDStandard::IncrementalSVDStandard(
26  Options options,
27  const std::string& basis_file_name) :
28  IncrementalSVD(
29  options,
30  basis_file_name)
31 {
32  // If the state of the SVD is to be restored, do it now. The base class,
33  // IncrementalSVD, has already opened the database and restored the state
34  // common to all incremental algorithms. This particular class has no other
35  // state to read and only needs to compute the basis. If the database could
36  // not be found then we can not restore the state.
37  if (options.restore_state && d_state_database) {
38  // Close and delete the database.
39  d_state_database->close();
40  delete d_state_database;
41 
42  // Compute the basis.
43  computeBasis();
44  }
45 }
46 
47 IncrementalSVDStandard::~IncrementalSVDStandard()
48 {
49  // If the state of the SVD is to be saved, then create the database now.
50  // The IncrementalSVD base class destructor will save d_S and d_U. This
51  // derived class has no specific state to save.
52  //
53  // If there are multiple time intervals then saving and restoring the state
54  // does not make sense as there is not one, all encompassing, basis.
55  if (d_save_state && (!isFirstSample())) {
56  // Create state database file.
57  d_state_database = new HDFDatabase();
58  d_state_database->create(d_state_file_name);
59  }
60 }
61 
62 void
63 IncrementalSVDStandard::buildInitialSVD(
64  double* u)
65 {
66  CAROM_VERIFY(u != 0);
67 
68  // Build d_S for this new time interval.
69  d_S.reset(new Vector(1, false));
70  Vector u_vec(u, d_dim, true);
71  double norm_u = u_vec.norm();
72  d_S->item(0) = norm_u;
73 
74  // Build d_U for this new time interval.
75  d_U.reset(new Matrix(d_dim, 1, true));
76  for (int i = 0; i < d_dim; ++i) {
77  d_U->item(i, 0) = u[i]/norm_u;
78  }
79 
80  // Build d_W for this new time interval.
81  if (d_update_right_SV) {
82  d_W.reset(new Matrix(1, 1, false));
83  d_W->item(0, 0) = 1.0;
84  }
85 
86  // Compute the basis vectors for this time interval.
87  computeBasis();
88 
89  // We now have the first sample for the new time interval.
90  d_num_samples = 1;
91 }
92 
93 void
94 IncrementalSVDStandard::computeBasis()
95 {
96  /* Invalidate existing cached basis and update cached basis */
97  d_basis.reset(new Matrix(*d_U));
98 
99  if (d_update_right_SV)
100  {
101  d_basis_right.reset(new Matrix(*d_W));
102  }
103 }
104 
105 void
106 IncrementalSVDStandard::addLinearlyDependentSample(
107  const Matrix & A,
108  const Matrix & W,
109  const Matrix & sigma)
110 {
111  // Chop a row and a column off of A to form Amod. Also form
112  // d_S by chopping a row and a column off of sigma.
113  Matrix Amod(d_num_samples, d_num_samples, false);
114  for (int row = 0; row < d_num_samples; ++row) {
115  for (int col = 0; col < d_num_samples; ++col) {
116  Amod.item(row, col) = A.item(row, col);
117  if (row == col)
118  {
119  d_S->item(col) = sigma.item(row, col);
120  }
121  }
122  }
123 
124  // Multiply d_U and Amod and put result into d_U.
125  Matrix *U_times_Amod = new Matrix(d_U->numRows(), Amod.numColumns(), false);
126  d_U->mult(Amod, *U_times_Amod);
127  d_U.reset(U_times_Amod);
128 
129  // Chop a column off of W to form Wmod.
130  if (d_update_right_SV) {
131  Matrix *new_d_W = new Matrix(d_num_rows_of_W+1, d_num_samples, false);
132  for (int row = 0; row < d_num_rows_of_W; ++row) {
133  for (int col = 0; col < d_num_samples; ++col) {
134  double new_d_W_entry = 0.0;
135  for (int entry = 0; entry < d_num_samples; ++entry) {
136  new_d_W_entry += d_W->item(row, entry)*W.item(entry, col);
137  }
138  new_d_W->item(row, col) = new_d_W_entry;
139  }
140  }
141  for (int col = 0; col < d_num_samples; ++col) {
142  new_d_W->item(d_num_rows_of_W, col) = W.item(d_num_samples, col);
143  }
144  d_W.reset(new_d_W);
145  ++d_num_rows_of_W;
146  }
147 
148  // Reorthogonalize if necessary.
149  long int max_U_dim;
150  if (d_num_samples > d_total_dim) {
151  max_U_dim = d_num_samples;
152  }
153  else {
154  max_U_dim = d_total_dim;
155  }
156  if (fabs(checkOrthogonality(*d_U)) >
157  std::numeric_limits<double>::epsilon()*static_cast<double>(max_U_dim)) {
158  d_U->orthogonalize();
159  }
160 }
161 
162 void
163 IncrementalSVDStandard::addNewSample(
164  const Vector & j,
165  const Matrix & A,
166  const Matrix & W,
167  const Matrix & sigma)
168 {
169  // Add j as a new column of d_U. Then multiply by A to form a new d_U.
170  Matrix tmp(d_dim, d_num_samples+1, true);
171  for (int row = 0; row < d_dim; ++row) {
172  for (int col = 0; col < d_num_samples; ++col) {
173  tmp.item(row, col) = d_U->item(row, col);
174  }
175  tmp.item(row, d_num_samples) = j.item(row);
176  }
177  tmp.mult(A, *d_U);
178 
179  if (d_update_right_SV) {
180  Matrix *new_d_W = new Matrix(d_num_rows_of_W+1, d_num_samples+1, false);
181  for (int row = 0; row < d_num_rows_of_W; ++row) {
182  for (int col = 0; col < d_num_samples+1; ++col) {
183  double new_d_W_entry = 0.0;
184  for (int entry = 0; entry < d_num_samples; ++entry) {
185  new_d_W_entry += d_W->item(row, entry)*W.item(entry, col);
186  }
187  new_d_W->item(row, col) = new_d_W_entry;
188  }
189  }
190  for (int col = 0; col < d_num_samples+1; ++col) {
191  new_d_W->item(d_num_rows_of_W, col) = W.item(d_num_samples, col);
192  }
193  d_W.reset(new_d_W);
194  }
195 
196  int num_dim = std::min(sigma.numRows(), sigma.numColumns());
197  d_S.reset(new Vector(num_dim, false));
198  for (int i = 0; i < num_dim; i++) {
199  d_S->item(i) = sigma.item(i,i);
200  }
201 
202  // We now have another sample.
203  ++d_num_samples;
204  ++d_num_rows_of_W;
205 
206  // Reorthogonalize if necessary.
207  long int max_U_dim;
208  if (d_num_samples > d_total_dim) {
209  max_U_dim = d_num_samples;
210  }
211  else {
212  max_U_dim = d_total_dim;
213  }
214  if (fabs(checkOrthogonality(*d_U)) >
215  std::numeric_limits<double>::epsilon()*static_cast<double>(max_U_dim)) {
216  d_U->orthogonalize();
217  }
218  if (d_update_right_SV) {
219  if (fabs(checkOrthogonality(*d_W)) >
220  std::numeric_limits<double>::epsilon()*d_num_samples) {
221  d_W->orthogonalize();
222  }
223  }
224 }
225 
226 }