14 #include "IncrementalSVDBrand.h"
15 #include "utils/HDFDatabase.h"
24 IncrementalSVDBrand::IncrementalSVDBrand(
26 const std::string& basis_file_name) :
30 d_singular_value_tol(options.singular_value_tol)
32 CAROM_VERIFY(options.singular_value_tol >= 0);
39 if (options.restore_state && d_state_database) {
42 d_state_database->getInteger(
"Up_num_rows", num_rows);
44 d_state_database->getInteger(
"Up_num_cols", num_cols);
45 d_Up.reset(
new Matrix(num_rows, num_cols,
true));
46 d_state_database->getDoubleArray(
"Up",
51 d_state_database->close();
52 delete d_state_database;
59 IncrementalSVDBrand::~IncrementalSVDBrand()
67 if (d_save_state && (!isFirstSample())) {
70 d_state_database->create(d_state_file_name);
73 int num_rows = d_Up->numRows();
74 d_state_database->putInteger(
"Up_num_rows", num_rows);
75 int num_cols = d_Up->numColumns();
76 d_state_database->putInteger(
"Up_num_cols", num_cols);
77 d_state_database->putDoubleArray(
"Up",
83 std::shared_ptr<const Matrix>
84 IncrementalSVDBrand::getSpatialBasis()
88 CAROM_ASSERT(d_basis !=
nullptr);
92 std::shared_ptr<const Matrix>
93 IncrementalSVDBrand::getTemporalBasis()
95 updateTemporalBasis();
97 CAROM_ASSERT(d_basis_right != 0);
102 IncrementalSVDBrand::buildInitialSVD(
105 CAROM_VERIFY(u != 0);
108 d_S.reset(
new Vector(1,
false));
109 Vector u_vec(u, d_dim,
true);
110 double norm_u = u_vec.norm();
111 d_S->item(0) = norm_u;
114 d_Up.reset(
new Matrix(1, 1,
false));
115 d_Up->item(0, 0) = 1.0;
118 d_U.reset(
new Matrix(d_dim, 1,
true));
119 for (
int i = 0; i < d_dim; ++i) {
120 d_U->item(i, 0) = u[i]/norm_u;
124 if (d_update_right_SV) {
125 d_W.reset(
new Matrix(1, 1,
false));
126 d_W->item(0, 0) = 1.0;
136 IncrementalSVDBrand::buildIncrementalSVD(
137 double* u,
bool add_without_increase)
139 CAROM_VERIFY(u != 0);
143 Vector u_vec(u, d_dim,
true);
144 Vector e_proj(u, d_dim,
true);
146 Vector tmp(d_U->numColumns(),
false);
147 Vector tmp2(d_U->numRows(),
true);
148 d_U->transposeMult(e_proj, tmp);
149 d_U->mult(tmp, tmp2);
151 d_U->transposeMult(e_proj, tmp);
152 d_U->mult(tmp, tmp2);
155 double k = e_proj.inner_product(e_proj);
157 if(d_rank == 0) printf(
"linearly dependent sample!\n");
166 bool linearly_dependent_sample;
167 if ( k < d_linearity_tol ) {
169 std::cout <<
"linearly dependent sample! k = " << k <<
"\n";
170 std::cout <<
"d_linearity_tol = " << d_linearity_tol <<
"\n";
173 linearly_dependent_sample =
true;
174 }
else if ( d_num_samples >= d_max_basis_dimension || add_without_increase ) {
176 linearly_dependent_sample =
true;
184 else if (d_num_samples >= d_total_dim) {
185 linearly_dependent_sample =
true;
188 linearly_dependent_sample =
false;
193 Vector U_mult_u(d_U->transposeMult(u_vec)->getData(), d_num_samples,
false);
194 Vector l(d_Up->numColumns(),
false);
195 d_Up->transposeMult(U_mult_u, l);
202 bool result = svd(Q, A, sigma, W);
213 if ((linearly_dependent_sample && !d_skip_linearly_dependent) ) {
216 if(d_rank == 0) std::cout <<
"adding linearly dependent sample!\n";
217 addLinearlyDependentSample(*A, *W, *sigma);
220 else if (!linearly_dependent_sample) {
224 Vector* j =
new Vector(e_proj.getData(), d_dim,
false);
225 for (
int i = 0; i < d_dim; ++i) {
231 addNewSample(*j, *A, *W, *sigma);
246 IncrementalSVDBrand::updateSpatialBasis()
248 d_basis = d_U->mult(*d_Up);
251 if ( (d_singular_value_tol != 0.0) &&
252 (d_S->item(d_num_samples-1) < d_singular_value_tol) &&
253 (d_num_samples != 1) ) {
257 "removing a spatial basis corresponding to the small singular value!\n";
260 Matrix* d_basis_new =
new Matrix(d_dim, d_num_samples-1,
261 d_basis->distributed());
262 for (
int row = 0; row < d_dim; ++row) {
263 for (
int col = 0; col < d_num_samples-1; ++col) {
264 d_basis_new->item(row, col) = d_basis->item(row,col);
267 d_basis.reset(d_basis_new);
272 if (fabs(checkOrthogonality(*d_basis)) >
273 std::numeric_limits<double>::epsilon()*
static_cast<double>(d_num_samples)) {
274 d_basis->orthogonalize();
279 IncrementalSVDBrand::updateTemporalBasis()
281 d_basis_right.reset(
new Matrix(*d_W));
284 if ( (d_singular_value_tol != 0.0) &&
285 (d_S->item(d_num_samples-1) < d_singular_value_tol) &&
286 (d_num_samples != 1) ) {
290 "removing a temporal basis corresponding to the small singular value!\n";
293 Matrix* d_basis_right_new =
new Matrix(d_num_rows_of_W, d_num_samples-1,
294 d_basis_right->distributed());
295 for (
int row = 0; row < d_num_rows_of_W; ++row) {
296 for (
int col = 0; col < d_num_samples-1; ++col) {
297 d_basis_right_new->item(row, col) = d_basis_right->item(row,col);
300 d_basis_right.reset(d_basis_right_new);
305 if (fabs(checkOrthogonality(*d_basis_right)) >
306 std::numeric_limits<double>::epsilon()*d_num_samples) {
307 d_basis_right->orthogonalize();
312 IncrementalSVDBrand::computeBasis()
315 std::cout <<
"d_num_samples = " << d_num_samples <<
"\n";
316 std::cout <<
"d_num_rows_of_W = " << d_num_rows_of_W <<
"\n";
317 std::cout <<
"d_singular_value_tol = " << d_singular_value_tol <<
"\n";
318 std::cout <<
"smallest SV = " << d_S->item(d_num_samples-1) <<
"\n";
319 if (d_num_samples > 1) {
320 std::cout <<
"next smallest SV = " << d_S->item(d_num_samples-2) <<
"\n";
324 updateSpatialBasis();
325 if (d_update_right_SV)
327 updateTemporalBasis();
331 if ( (d_singular_value_tol != 0.0) &&
332 (d_S->item(d_num_samples-1) < d_singular_value_tol) &&
333 (d_num_samples != 1) ) {
340 IncrementalSVDBrand::addLinearlyDependentSample(
343 const Matrix & sigma)
347 Matrix Amod(d_num_samples, d_num_samples,
false);
348 for (
int row = 0; row < d_num_samples; ++row) {
349 for (
int col = 0; col < d_num_samples; ++col) {
350 Amod.item(row, col) = A.item(row, col);
353 d_S->item(col) = sigma.item(row, col);
359 Matrix *Up_times_Amod =
new Matrix(d_Up->numRows(), Amod.numColumns(),
false);
360 d_Up->mult(Amod, *Up_times_Amod);
361 d_Up.reset(Up_times_Amod);
363 if (d_update_right_SV) {
369 Matrix *new_d_W =
new Matrix(d_num_rows_of_W+1, d_num_samples,
false);
370 for (
int row = 0; row < d_num_rows_of_W; ++row) {
371 for (
int col = 0; col < d_num_samples; ++col) {
372 double new_d_W_entry = 0.0;
373 for (
int entry = 0; entry < d_num_samples; ++entry) {
374 new_d_W_entry += d_W->item(row, entry)*W.item(entry, col);
376 new_d_W->item(row, col) = new_d_W_entry;
379 for (
int col = 0; col < d_num_samples; ++col) {
380 new_d_W->item(d_num_rows_of_W, col) = W.item(d_num_samples, col);
389 IncrementalSVDBrand::addNewSample(
393 const Matrix & sigma)
396 Matrix* newU =
new Matrix(d_dim, d_num_samples+1,
true);
397 for (
int row = 0; row < d_dim; ++row) {
398 for (
int col = 0; col < d_num_samples; ++col) {
399 newU->item(row, col) = d_U->item(row, col);
401 newU->item(row, d_num_samples) = j.item(row);
405 if (d_update_right_SV) {
411 Matrix *new_d_W =
new Matrix(d_num_rows_of_W+1, d_num_samples+1,
false);
412 for (
int row = 0; row < d_num_rows_of_W; ++row) {
413 for (
int col = 0; col < d_num_samples+1; ++col) {
414 double new_d_W_entry = 0.0;
415 for (
int entry = 0; entry < d_num_samples; ++entry) {
416 new_d_W_entry += d_W->item(row, entry)*W.item(entry, col);
418 new_d_W->item(row, col) = new_d_W_entry;
421 for (
int col = 0; col < d_num_samples+1; ++col) {
422 new_d_W->item(d_num_rows_of_W, col) = W.item(d_num_samples, col);
432 Matrix* new_d_Up =
new Matrix(d_num_samples+1, d_num_samples+1,
false);
433 for (
int row = 0; row < d_num_samples; ++row) {
434 for (
int col = 0; col < d_num_samples+1; ++col) {
435 double new_d_Up_entry = 0.0;
436 for (
int entry = 0; entry < d_num_samples; ++entry) {
437 new_d_Up_entry += d_Up->item(row, entry)*A.item(entry, col);
439 new_d_Up->item(row, col) = new_d_Up_entry;
442 for (
int col = 0; col < d_num_samples+1; ++col) {
443 new_d_Up->item(d_num_samples, col) = A.item(d_num_samples, col);
445 d_Up.reset(new_d_Up);
448 int num_dim = std::min(sigma.numRows(), sigma.numColumns());
449 d_S.reset(
new Vector(num_dim,
false));
450 for (
int i = 0; i < num_dim; i++) {
451 d_S->item(i) = sigma.item(i,i);
460 if (d_num_samples > d_total_dim) {
461 max_U_dim = d_num_samples;
464 max_U_dim = d_total_dim;
466 if (fabs(checkOrthogonality(*d_Up)) >
467 std::numeric_limits<double>::epsilon()*
static_cast<double>(max_U_dim)) {
468 d_Up->orthogonalize();
470 if (fabs(checkOrthogonality(*d_U)) >
471 std::numeric_limits<double>::epsilon()*
static_cast<double>(max_U_dim)) {
472 d_U->orthogonalize();
475 if(d_update_right_SV)
477 if (fabs(checkOrthogonality(*d_W)) >
478 std::numeric_limits<double>::epsilon()*d_num_samples) {
479 d_W->orthogonalize();