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 = 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 = 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 = 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  delete d_basis;
98  d_basis = new Matrix(*d_U);
99 
100  if (d_update_right_SV)
101  {
102  delete d_basis_right;
103  d_basis_right = new Matrix(*d_W);
104  }
105 }
106 
107 void
108 IncrementalSVDStandard::addLinearlyDependentSample(
109  const Matrix* A,
110  const Matrix* W,
111  const Matrix* sigma)
112 {
113  CAROM_VERIFY(A != 0);
114  CAROM_VERIFY(sigma != 0);
115 
116  // Chop a row and a column off of A to form Amod. Also form
117  // d_S by chopping a row and a column off of sigma.
118  Matrix Amod(d_num_samples, d_num_samples, false);
119  for (int row = 0; row < d_num_samples; ++row) {
120  for (int col = 0; col < d_num_samples; ++col) {
121  Amod.item(row, col) = A->item(row, col);
122  if (row == col)
123  {
124  d_S->item(col) = sigma->item(row, col);
125  }
126  }
127  }
128 
129  // Multiply d_U and Amod and put result into d_U.
130  Matrix* U_times_Amod = d_U->mult(Amod);
131  delete d_U;
132  d_U = U_times_Amod;
133 
134  // Chop a column off of W to form Wmod.
135  Matrix* new_d_W;
136  if (d_update_right_SV) {
137  new_d_W = new Matrix(d_num_rows_of_W+1, d_num_samples, false);
138  for (int row = 0; row < d_num_rows_of_W; ++row) {
139  for (int col = 0; col < d_num_samples; ++col) {
140  double new_d_W_entry = 0.0;
141  for (int entry = 0; entry < d_num_samples; ++entry) {
142  new_d_W_entry += d_W->item(row, entry)*W->item(entry, col);
143  }
144  new_d_W->item(row, col) = new_d_W_entry;
145  }
146  }
147  for (int col = 0; col < d_num_samples; ++col) {
148  new_d_W->item(d_num_rows_of_W, col) = W->item(d_num_samples, col);
149  }
150  delete d_W;
151  d_W = new_d_W;
152  ++d_num_rows_of_W;
153  }
154 
155  // Reorthogonalize if necessary.
156  long int max_U_dim;
157  if (d_num_samples > d_total_dim) {
158  max_U_dim = d_num_samples;
159  }
160  else {
161  max_U_dim = d_total_dim;
162  }
163  if (fabs(checkOrthogonality(d_U)) >
164  std::numeric_limits<double>::epsilon()*static_cast<double>(max_U_dim)) {
165  d_U->orthogonalize();
166  }
167 }
168 
169 void
170 IncrementalSVDStandard::addNewSample(
171  const Vector* j,
172  const Matrix* A,
173  const Matrix* W,
174  Matrix* sigma)
175 {
176  // Add j as a new column of d_U. Then multiply by A to form a new d_U.
177  Matrix tmp(d_dim, d_num_samples+1, true);
178  for (int row = 0; row < d_dim; ++row) {
179  for (int col = 0; col < d_num_samples; ++col) {
180  tmp.item(row, col) = d_U->item(row, col);
181  }
182  tmp.item(row, d_num_samples) = j->item(row);
183  }
184  delete d_U;
185  d_U = tmp.mult(A);
186 
187  Matrix* new_d_W;
188  if (d_update_right_SV) {
189  new_d_W = new Matrix(d_num_rows_of_W+1, d_num_samples+1, false);
190  for (int row = 0; row < d_num_rows_of_W; ++row) {
191  for (int col = 0; col < d_num_samples+1; ++col) {
192  double new_d_W_entry = 0.0;
193  for (int entry = 0; entry < d_num_samples; ++entry) {
194  new_d_W_entry += d_W->item(row, entry)*W->item(entry, col);
195  }
196  new_d_W->item(row, col) = new_d_W_entry;
197  }
198  }
199  for (int col = 0; col < d_num_samples+1; ++col) {
200  new_d_W->item(d_num_rows_of_W, col) = W->item(d_num_samples, col);
201  }
202  delete d_W;
203  d_W = new_d_W;
204  }
205 
206  delete d_S;
207  int num_dim = std::min(sigma->numRows(), sigma->numColumns());
208  d_S = new Vector(num_dim, false);
209  for (int i = 0; i < num_dim; i++) {
210  d_S->item(i) = sigma->item(i,i);
211  }
212 
213  // We now have another sample.
214  ++d_num_samples;
215  ++d_num_rows_of_W;
216 
217  // Reorthogonalize if necessary.
218  long int max_U_dim;
219  if (d_num_samples > d_total_dim) {
220  max_U_dim = d_num_samples;
221  }
222  else {
223  max_U_dim = d_total_dim;
224  }
225  if (fabs(checkOrthogonality(d_U)) >
226  std::numeric_limits<double>::epsilon()*static_cast<double>(max_U_dim)) {
227  d_U->orthogonalize();
228  }
229  if (d_update_right_SV) {
230  if (fabs(checkOrthogonality(d_W)) >
231  std::numeric_limits<double>::epsilon()*d_num_samples) {
232  d_W->orthogonalize();
233  }
234  }
235 }
236 
237 }