From fc9d40701d1bdc125aaa92b7bd7f8ccc7d813176 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Tue, 16 Dec 2025 01:49:04 -0700 Subject: [PATCH 1/3] Replace VNL eigensystem with Eigen SVD for PCA computation Switch ParticleShapeStatistics::compute_modes() from VNL's vnl_symmetric_eigensystem to Eigen's BDCSVD algorithm. This provides: - Better numerical stability by computing SVD directly on the centered data matrix rather than forming the covariance matrix A^T*A first - Reduced dependency on legacy VNL library in favor of Eigen - Cleaner code using Eigen's built-in vector normalization The SVD singular values squared equal the eigenvalues, and the left singular vectors (U) correspond to the eigenvectors in particle space. Results are reversed to maintain ascending eigenvalue order for backward compatibility. Also add profiling instrumentation to compute_modes() and Studio main. --- Libs/Common/Profiling.cpp | 2 + Libs/Particles/ParticleShapeStatistics.cpp | 60 +++++++++++----------- Studio/main.cpp | 8 ++- 3 files changed, 38 insertions(+), 32 deletions(-) diff --git a/Libs/Common/Profiling.cpp b/Libs/Common/Profiling.cpp index c9649ab3e7..a77ed9c453 100644 --- a/Libs/Common/Profiling.cpp +++ b/Libs/Common/Profiling.cpp @@ -157,6 +157,8 @@ void Profiler::finalize() { write_trace_file(); } } + +//--------------------------------------------------------------------------- void Profiler::write_profile_report() { // Calculate total time double total_time_ms = elapsed_timer_.elapsed(); diff --git a/Libs/Particles/ParticleShapeStatistics.cpp b/Libs/Particles/ParticleShapeStatistics.cpp index 023a594c93..3f1f627712 100644 --- a/Libs/Particles/ParticleShapeStatistics.cpp +++ b/Libs/Particles/ParticleShapeStatistics.cpp @@ -7,6 +7,7 @@ #include #include "ExternalLibs/tinyxml/tinyxml.h" +#include "Profiling.h" #include "ShapeEvaluation.h" namespace shapeworks { @@ -577,49 +578,48 @@ int ParticleShapeStatistics::do_pca(std::shared_ptr project) { } //--------------------------------------------------------------------------- + int ParticleShapeStatistics::compute_modes() { + TIME_SCOPE("ParticleShapeStatistics::compute_modes"); SW_DEBUG("computing PCA modes"); - Eigen::MatrixXd A = points_minus_mean_.transpose() * points_minus_mean_ * (1.0 / ((double)(num_samples_ - 1))); - auto vnlA = vnl_matrix(A.data(), A.rows(), A.cols()); - vnl_symmetric_eigensystem symEigen(vnlA); + double scale = std::sqrt(num_samples_ - 1); + Eigen::BDCSVD svd(points_minus_mean_ / scale, Eigen::ComputeThinU); - Eigen::MatrixXd eigenSymEigenV = - Eigen::Map(symEigen.V.transpose().data_block(), symEigen.V.rows(), symEigen.V.cols()); - Eigen::VectorXd eigenSymEigenD = Eigen::Map(symEigen.D.data_block(), symEigen.D.rows(), 1); + Eigen::VectorXd eigenvalues_eigen = svd.singularValues().array().square(); - eigenvectors_ = points_minus_mean_ * eigenSymEigenV; - eigenvalues_.resize(num_samples_); + // U * S gives us the eigenvectors in particle space (like points_minus_mean_ * V did before) + // But we want them normalized, so just use U (which is already orthonormal) + eigenvectors_ = svd.matrixU() * scale; // Scale back to match original magnitudes - // normalize the eigenvectors - for (unsigned int i = 0; i < num_samples_; i++) { - double total = 0.0f; - for (unsigned int j = 0; j < num_dimensions_; j++) { - total += eigenvectors_(j, i) * eigenvectors_(j, i); - } - total = sqrt(total); + int num_modes = eigenvalues_eigen.size(); - for (unsigned int j = 0; j < num_dimensions_; j++) { - eigenvectors_(j, i) = eigenvectors_(j, i) / (total + 1.0e-15); - } + // normalize the eigenvectors + for (int i = 0; i < eigenvectors_.cols(); i++) { + eigenvectors_.col(i).normalize(); + } - eigenvalues_[i] = eigenSymEigenD(i); + // SVD returns values in descending order, but we need ascending order for backward compatibility + // Reverse both eigenvalues and eigenvector columns + eigenvalues_.resize(num_modes); + for (int i = 0; i < num_modes; i++) { + eigenvalues_[i] = eigenvalues_eigen[num_modes - 1 - i]; } + eigenvectors_ = eigenvectors_.rowwise().reverse().eval(); - float sum = 0.0; - for (unsigned int n = 0; n < num_samples_; n++) { - sum += eigenvalues_[(num_samples_ - 1) - n]; + // eigenvalues are now in ascending order (smallest to largest) + double sum = 0.0; + for (int n = 0; n < num_modes; n++) { + sum += eigenvalues_[n]; } - float sum2 = 0.0; - bool found = false; - for (unsigned int n = 0; n < num_samples_; n++) { - sum2 += eigenvalues_[(num_samples_ - 1) - n]; + // percent_variance_by_mode_ accumulates from largest eigenvalue (at end) to smallest + // to match the old behavior + percent_variance_by_mode_.clear(); + double sum2 = 0.0; + for (int n = num_modes - 1; n >= 0; n--) { + sum2 += eigenvalues_[n]; percent_variance_by_mode_.push_back(sum2 / sum); - - if ((sum2 / sum) >= 0.95 && found == false) { - found = true; - } } return 0; diff --git a/Studio/main.cpp b/Studio/main.cpp index e63c4352e3..d5ccb2649c 100644 --- a/Studio/main.cpp +++ b/Studio/main.cpp @@ -10,6 +10,8 @@ #include #include +#include "Profiling.h" + // itk #include @@ -77,8 +79,8 @@ static void new_log() { int main(int argc, char** argv) { // tbb::task_scheduler_init init(1); + TIME_SCOPE("ShapeWorksStudio"); try { - #ifdef Q_OS_MACOS // Prevent cursor crashes on Apple Silicon qputenv("QT_MAC_DISABLE_NATIVE_CURSORS", "1"); @@ -148,7 +150,9 @@ int main(int argc, char** argv) { app.file_open_callback_(app.stored_filename_); } - return app.exec(); + auto rc = app.exec(); + TIME_FINALIZE(); + return rc; } catch (itk::ExceptionObject& excep) { std::cerr << excep << std::endl; } catch (std::exception& e) { From e9d84e99c8f8d8ed0c6a9384bc31495879d6599a Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Wed, 17 Dec 2025 10:17:10 -0700 Subject: [PATCH 2/3] Apply Eigen approach to MLCA functions as well. --- Libs/Particles/ParticleShapeStatistics.cpp | 96 +++++++++++----------- 1 file changed, 47 insertions(+), 49 deletions(-) diff --git a/Libs/Particles/ParticleShapeStatistics.cpp b/Libs/Particles/ParticleShapeStatistics.cpp index 3f1f627712..53cf942527 100644 --- a/Libs/Particles/ParticleShapeStatistics.cpp +++ b/Libs/Particles/ParticleShapeStatistics.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include "ExternalLibs/tinyxml/tinyxml.h" #include "Profiling.h" @@ -292,62 +291,57 @@ void ParticleShapeStatistics::compute_multi_level_analysis_statistics(std::vecto //--------------------------------------------------------------------------- int ParticleShapeStatistics::compute_shape_dev_modes_for_mca() { - unsigned int m = points_minus_mean_shape_dev_.rows(); - Eigen::MatrixXd A = - points_minus_mean_shape_dev_.transpose() * points_minus_mean_shape_dev_ * (1.0 / ((double)(num_samples_ - 1))); + // Use SVD to compute PCA. For X = U * S * V^T: + // - The covariance matrix X^T * X / (n-1) has eigenvalues S^2 / (n-1) and eigenvectors V + // - The old code computed eigenvectors_ = X * V = U * S + Eigen::BDCSVD svd(points_minus_mean_shape_dev_, Eigen::ComputeThinU | Eigen::ComputeThinV); - vnl_matrix vnlA = vnl_matrix(A.data(), A.rows(), A.cols()); - vnl_symmetric_eigensystem symEigen(vnlA); - Eigen::MatrixXd shape_dev_eigenSymEigenV = - Eigen::Map(symEigen.V.transpose().data_block(), symEigen.V.rows(), symEigen.V.cols()); - Eigen::VectorXd shape_dev_eigenSymEigenD = Eigen::Map(symEigen.D.data_block(), symEigen.D.rows(), 1); + Eigen::VectorXd eigenvalues_eigen = svd.singularValues().array().square() / (num_samples_ - 1); + int num_modes = eigenvalues_eigen.size(); - eigenvectors_shape_dev_ = points_minus_mean_shape_dev_ * shape_dev_eigenSymEigenV; - eigenvalues_shape_dev_.resize(num_samples_); + // Compute eigenvectors_ = X * V = U * S (matches old behavior before normalization) + eigenvectors_shape_dev_ = svd.matrixU() * svd.singularValues().asDiagonal(); - for (unsigned int i = 0; i < num_samples_; i++) { - double total = 0.0f; - for (unsigned int j = 0; j < m; j++) { - total += eigenvectors_shape_dev_(j, i) * eigenvectors_shape_dev_(j, i); - } - total = sqrt(total); + // normalize the eigenvectors + for (int i = 0; i < eigenvectors_shape_dev_.cols(); i++) { + eigenvectors_shape_dev_.col(i).normalize(); + } - for (unsigned int j = 0; j < m; j++) { - eigenvectors_shape_dev_(j, i) = eigenvectors_shape_dev_(j, i) / (total + 1.0e-15); - } - eigenvalues_shape_dev_[i] = shape_dev_eigenSymEigenD(i); + // SVD returns values in descending order, but we need ascending order for backward compatibility + eigenvalues_shape_dev_.resize(num_modes); + for (int i = 0; i < num_modes; i++) { + eigenvalues_shape_dev_[i] = eigenvalues_eigen[num_modes - 1 - i]; } + eigenvectors_shape_dev_ = eigenvectors_shape_dev_.rowwise().reverse().eval(); + return 0; } //--------------------------------------------------------------------------- int ParticleShapeStatistics::compute_relative_pose_modes_for_mca() { - unsigned int m = points_minus_mean_rel_pose_.rows(); - Eigen::MatrixXd A = - points_minus_mean_rel_pose_.transpose() * points_minus_mean_rel_pose_ * (1.0 / ((double)(num_samples_ - 1))); - auto vnlA = vnl_matrix(A.data(), A.rows(), A.cols()); - vnl_symmetric_eigensystem symEigen(vnlA); - Eigen::MatrixXd rel_pose_eigenSymEigenV = - Eigen::Map(symEigen.V.transpose().data_block(), symEigen.V.rows(), symEigen.V.cols()); + // Use SVD to compute PCA. For X = U * S * V^T: + // - The covariance matrix X^T * X / (n-1) has eigenvalues S^2 / (n-1) and eigenvectors V + // - The old code computed eigenvectors_ = X * V = U * S + Eigen::BDCSVD svd(points_minus_mean_rel_pose_, Eigen::ComputeThinU | Eigen::ComputeThinV); - Eigen::VectorXd rel_pose_eigenSymEigenD = Eigen::Map(symEigen.D.data_block(), symEigen.D.rows(), 1); + Eigen::VectorXd eigenvalues_eigen = svd.singularValues().array().square() / (num_samples_ - 1); + int num_modes = eigenvalues_eigen.size(); - eigenvectors_rel_pose_ = points_minus_mean_rel_pose_ * rel_pose_eigenSymEigenV; - eigenvalues_rel_pose_.resize(num_samples_); + // Compute eigenvectors_ = X * V = U * S (matches old behavior before normalization) + eigenvectors_rel_pose_ = svd.matrixU() * svd.singularValues().asDiagonal(); - for (unsigned int i = 0; i < num_samples_; i++) { - double total = 0.0f; - for (unsigned int j = 0; j < m; j++) { - total += eigenvectors_rel_pose_(j, i) * eigenvectors_rel_pose_(j, i); - } - total = sqrt(total); - - for (unsigned int j = 0; j < m; j++) { - eigenvectors_rel_pose_(j, i) = eigenvectors_rel_pose_(j, i) / (total + 1.0e-15); - } + // normalize the eigenvectors + for (int i = 0; i < eigenvectors_rel_pose_.cols(); i++) { + eigenvectors_rel_pose_.col(i).normalize(); + } - eigenvalues_rel_pose_[i] = rel_pose_eigenSymEigenD(i); + // SVD returns values in descending order, but we need ascending order for backward compatibility + eigenvalues_rel_pose_.resize(num_modes); + for (int i = 0; i < num_modes; i++) { + eigenvalues_rel_pose_[i] = eigenvalues_eigen[num_modes - 1 - i]; } + eigenvectors_rel_pose_ = eigenvectors_rel_pose_.rowwise().reverse().eval(); + return 0; } @@ -583,17 +577,21 @@ int ParticleShapeStatistics::compute_modes() { TIME_SCOPE("ParticleShapeStatistics::compute_modes"); SW_DEBUG("computing PCA modes"); - double scale = std::sqrt(num_samples_ - 1); - Eigen::BDCSVD svd(points_minus_mean_ / scale, Eigen::ComputeThinU); + // Use SVD to compute PCA. For X = U * S * V^T: + // - The covariance matrix X^T * X / (n-1) has eigenvalues S^2 / (n-1) and eigenvectors V + // - The old code computed eigenvectors_ = X * V = U * S + Eigen::BDCSVD svd(points_minus_mean_, Eigen::ComputeThinU | Eigen::ComputeThinV); - Eigen::VectorXd eigenvalues_eigen = svd.singularValues().array().square(); - - // U * S gives us the eigenvectors in particle space (like points_minus_mean_ * V did before) - // But we want them normalized, so just use U (which is already orthonormal) - eigenvectors_ = svd.matrixU() * scale; // Scale back to match original magnitudes + // Eigenvalues of X^T * X / (n-1) = singular_values^2 / (n-1) + Eigen::VectorXd eigenvalues_eigen = svd.singularValues().array().square() / (num_samples_ - 1); + // Eigenvectors in particle space: X * V = U * S + // SVD returns singular values in descending order, so we need to reverse for ascending order int num_modes = eigenvalues_eigen.size(); + // Compute eigenvectors_ = X * V = U * S (matches old behavior before normalization) + eigenvectors_ = svd.matrixU() * svd.singularValues().asDiagonal(); + // normalize the eigenvectors for (int i = 0; i < eigenvectors_.cols(); i++) { eigenvectors_.col(i).normalize(); From 75eda45472f56ea05aebc8f2d595212a57cc6125 Mon Sep 17 00:00:00 2001 From: Alan Morris Date: Wed, 17 Dec 2025 12:48:19 -0700 Subject: [PATCH 3/3] Fix eigenvector sign ambiguity in Eigen SVD PCA implementation The switch from VNL's vnl_symmetric_eigensystem to Eigen's BDCSVD introduced test failures due to eigenvector sign ambiguity. In PCA, eigenvectors are only determined up to a sign (both v and -v are valid), and different libraries may return either arbitrarily. Add a consistent sign convention: make the first element of each eigenvector positive. This ensures deterministic results regardless of the underlying linear algebra implementation. Update test baselines to match the new consistent sign convention. This way if we switch to another implementation later, we can keep the results consistent. --- Libs/Particles/ParticleShapeStatistics.cpp | 18 +- .../tps_mode-00_sample-000_dense.vtk | 4 +- .../tps_mode-00_sample-001_dense.vtk | 4 +- .../tps_mode-00_sample-002_dense.vtk | 4 +- .../analyze/analysis_baseline.json | 768 +++++++++--------- 5 files changed, 405 insertions(+), 393 deletions(-) diff --git a/Libs/Particles/ParticleShapeStatistics.cpp b/Libs/Particles/ParticleShapeStatistics.cpp index 53cf942527..f9f48efd6b 100644 --- a/Libs/Particles/ParticleShapeStatistics.cpp +++ b/Libs/Particles/ParticleShapeStatistics.cpp @@ -302,9 +302,13 @@ int ParticleShapeStatistics::compute_shape_dev_modes_for_mca() { // Compute eigenvectors_ = X * V = U * S (matches old behavior before normalization) eigenvectors_shape_dev_ = svd.matrixU() * svd.singularValues().asDiagonal(); - // normalize the eigenvectors + // normalize the eigenvectors and enforce sign convention + // (make first element positive to match VNL eigensystem convention) for (int i = 0; i < eigenvectors_shape_dev_.cols(); i++) { eigenvectors_shape_dev_.col(i).normalize(); + if (eigenvectors_shape_dev_(0, i) < 0) { + eigenvectors_shape_dev_.col(i) *= -1; + } } // SVD returns values in descending order, but we need ascending order for backward compatibility @@ -330,9 +334,13 @@ int ParticleShapeStatistics::compute_relative_pose_modes_for_mca() { // Compute eigenvectors_ = X * V = U * S (matches old behavior before normalization) eigenvectors_rel_pose_ = svd.matrixU() * svd.singularValues().asDiagonal(); - // normalize the eigenvectors + // normalize the eigenvectors and enforce sign convention + // (make first element positive to match VNL eigensystem convention) for (int i = 0; i < eigenvectors_rel_pose_.cols(); i++) { eigenvectors_rel_pose_.col(i).normalize(); + if (eigenvectors_rel_pose_(0, i) < 0) { + eigenvectors_rel_pose_.col(i) *= -1; + } } // SVD returns values in descending order, but we need ascending order for backward compatibility @@ -592,9 +600,13 @@ int ParticleShapeStatistics::compute_modes() { // Compute eigenvectors_ = X * V = U * S (matches old behavior before normalization) eigenvectors_ = svd.matrixU() * svd.singularValues().asDiagonal(); - // normalize the eigenvectors + // normalize the eigenvectors and enforce sign convention + // (make first element positive to match VNL eigensystem convention) for (int i = 0; i < eigenvectors_.cols(); i++) { eigenvectors_.col(i).normalize(); + if (eigenvectors_(0, i) < 0) { + eigenvectors_.col(i) *= -1; + } } // SVD returns values in descending order, but we need ascending order for backward compatibility diff --git a/Testing/data/reconstruct_pca_python/tps_mode-00_sample-000_dense.vtk b/Testing/data/reconstruct_pca_python/tps_mode-00_sample-000_dense.vtk index 3a30007838..dda48ed7b4 100644 --- a/Testing/data/reconstruct_pca_python/tps_mode-00_sample-000_dense.vtk +++ b/Testing/data/reconstruct_pca_python/tps_mode-00_sample-000_dense.vtk @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a40f757b38409c3bff3ff3f15acda4597a695889e83f4c29e4b76183f7688768 -size 56666 +oid sha256:8289ef4063092ae299ae7fbcaaf673884661c6493afe5f3506f56c132525f565 +size 73323 diff --git a/Testing/data/reconstruct_pca_python/tps_mode-00_sample-001_dense.vtk b/Testing/data/reconstruct_pca_python/tps_mode-00_sample-001_dense.vtk index c9f2f67437..4981a54ad0 100644 --- a/Testing/data/reconstruct_pca_python/tps_mode-00_sample-001_dense.vtk +++ b/Testing/data/reconstruct_pca_python/tps_mode-00_sample-001_dense.vtk @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:547770a438f1b239103719dc98d54aeb289c665017a37e3098266054b4050b5a -size 56666 +oid sha256:5af6e305291ee6b7790399d499a4594af087fe7b9f6584a55bfba8f820a9b992 +size 72872 diff --git a/Testing/data/reconstruct_pca_python/tps_mode-00_sample-002_dense.vtk b/Testing/data/reconstruct_pca_python/tps_mode-00_sample-002_dense.vtk index 2bad250420..4aaec5deaf 100644 --- a/Testing/data/reconstruct_pca_python/tps_mode-00_sample-002_dense.vtk +++ b/Testing/data/reconstruct_pca_python/tps_mode-00_sample-002_dense.vtk @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f1ffb527bd7116b6e9378d40dcbe55ac356eedf3e604cc63ed4a9464696ce8f3 -size 56666 +oid sha256:85d9be22f479b528dd602d555582d6948cfefb03aacdfb79177406eeacdb316b +size 72770 diff --git a/Testing/data/shapeworksTests/analyze/analysis_baseline.json b/Testing/data/shapeworksTests/analyze/analysis_baseline.json index 29f4441371..825d289adf 100644 --- a/Testing/data/shapeworksTests/analyze/analysis_baseline.json +++ b/Testing/data/shapeworksTests/analyze/analysis_baseline.json @@ -204,390 +204,390 @@ -0.117299, 0.000263, -0.055344, - -0.071718, - 0.008819, - 0.054672, - 0.015432, - 0.030976, - 0.0758, - 0.008265, - 0.014497, - -0.096481, - 0.090083, - -0.010936, - -0.057455, - -0.004509, - -0.009555, - -0.015099, - -0.124912, - 0.001339, - 0.200161, - -0.011805, - 0.021756, - -0.042494, - 0.027702, - 0.006524, - 0.197164, - -0.016178, - 0.059881, - 0.185588, - 0.020978, - 0.041852, - -0.061387, - -0.020118, - -0.027282, - -0.12091, - 0.049469, - 0.028752, - -0.231728, - -0.036168, - -0.011999, - -0.008939, - 0.007228, - -0.002977, - 0.033564, - -0.010024, - 0.00966, - 0.044596, - 0.043678, - -0.019131, - -0.090613, - -0.04426, - -0.087199, - 0.131077, - 0.06443, - -0.011578, - 0.033969, - -0.059241, - -0.021002, - -0.079187, - 0.06259, - 0.005068, - -0.004954, - 0.010163, - -0.005719, - 0.037729, - 0.041705, - -0.004209, - 0.040269, - -0.004894, - -0.001695, - -0.051296, - 0.010001, - -0.012828, - 0.088202, - 0.003967, - 0.006604, - 0.049106, - 0.063331, - -0.012861, - 0.105234, - -0.019675, - -0.024241, - -0.211199, - 0.078568, - 0.030876, - -0.122076, - -0.022054, - 0.004784, - -0.047175, - 0.000978, - -0.032414, - 0.142987, - -0.053993, - 0.00592, - 0.049454, - 0.00449, - -0.015489, - -0.028956, - -0.070892, - -0.008697, - 0.089013, - 0.000696, - 0.039603, - 0.194077, - 0.012834, - 0.063908, - -0.149661, - 0.10558, - -0.018135, - -0.135092, - -0.007163, - -0.006242, - -0.044593, - 0.006535, - 0.001669, - 0.236749, - -0.05098, - -0.000486, - -0.114364, - -0.000405, - -0.011635, - 0.094436, - -0.031127, - 0.022272, - 0.079185, - -0.000593, - 0.005661, - -0.010237, - -0.053563, - 0.031454, - -0.180309, - 0.047137, - -0.059878, - -0.179391, - -0.031428, - -0.017074, - 0.030701, - 0.005562, - -0.000418, - 0.012365, - -0.013679, - 0.033032, - 0.00381, - 0.005151, - -0.024023, - -0.081194, - -0.07761, - 0.015196, - 0.133154, - 0.065255, - -0.03357, - 0.140788, - -0.013105, - 0.006519, - -0.204232, - 0.024026, - 0.023929, - -0.033823, - -0.044788, - -0.043984, - 0.029424, - 0.060313, - 0.008281, - 0.092494, - -0.004592, - 0.003231, - -0.018919, - 0.024515, - -0.006924, - -0.000745, - -0.0061, - 0.001543, - 0.011302, - 0.008656, - 0.013022, - 0.033043, - 0.041233, - -0.017999, - -0.258595, - 0.017567, - 0.024197, - -0.083855, - -0.051797, - -0.004024, - -0.071533, - -0.03116, - -0.007688, - 0.254467, - -0.042539, - 0.020792, - -0.026787, - 0.049473, - -0.026456, - -0.030912, - -0.195842, - -0.005242, - 0.082503, - -0.01499, - 0.003618, - -0.049112, - 0.051307, - -0.011834, - 0.019008, - 0.200098, - 0.059657, - -0.109592, - -0.006945, - -0.023641, - -0.001411, - -0.114409, - 0.020787, - 0.089155, - -0.010246, - -0.027716, - 0.023129, - -0.062988, - 0.05887, - -0.103139, - -0.085568, - 0.054059, - 0.003828, - 0.088452, - 0.091657, - -0.042975, - 0.00084, - 0.087786, - 0.039477, - 0.11335, - 0.084967, - -0.047143, - -0.087936, - 0.011047, - 0.048831, - 0.006249, - 0.016875, - -0.011941, - -0.05381, - 0.022219, - 0.054344, - 0.08878, - -0.052333, - 0.000392, - -0.105344, - -0.099578, - 0.087181, - -0.012334, - 0.03541, - -0.05933, - 0.098218, - -0.011336, - 0.095554, - 0.165198, - 0.011166, - -0.064269, - -0.007946, - -0.00755, - -0.037587, - 0.042181, - -0.006968, - -0.070807, - 0.011778, - -0.011303, - 0.019473, - -0.047049, - 0.04503, - -0.083796, - 0.009682, - -0.013804, - 0.010193, - -0.036569, - -0.060744, - -0.058283, - 0.054226, - -0.013443, - 0.077145, - 0.041329, - 0.077576, - -0.153684, - 0.017517, - 0.011849, - 0.058648, - -0.061664, - -0.020648, - -0.028756, - -0.181853, - 0.026616, - 0.008608, - 0.032139, - -0.034001, - -0.020492, - -0.168679, - -0.071058, - 0.100804, - -0.103743, - -0.043606, - -0.088188, - 0.02689, - -0.016334, - 0.039233, - 0.162523, - -0.075108, - -0.110318, - -0.007568, - 0.016935, - -0.014621, - -0.160262, - -0.036108, - -0.163532, - 0.054512, - -0.065763, - 0.064999, - -0.047337, - 0.044309, - -0.000516, - -0.092965, - 0.036485, - 0.002841, - 0.013774, - 0.010288, - -0.02474, - 0.133301, - 0.062872, - 0.13546, - 0.094675, - -0.09341, - 0.008637, - -0.10444, - -0.035703, - 0.036872, - 0.014402, - 4.3e-05, - 0.017422, - -0.045839, - 0.058935, - 0.044966, - 0.045974, - -0.000507, - 0.055395, - -0.132301, - 0.081356, - 0.094584, - -0.101946, - -0.059299, - -0.144526, - 0.186208, - -0.078314, - 0.144836, - 0.101824, - 0.016033, - 0.008788, - -0.094889, - -0.061311, - 0.012358, - -0.075019, - 0.028781, - -0.138916, - 0.000119, - 0.004287, - -0.002651, - 0.053312, - -0.007765, - -0.052629, - -0.025514, - -0.002528, - 0.000727, - 0.015146, - -0.001421, - -0.066357, - 0.166622, - -0.046622, - 0.096597, - 0.078581, - 0.026191, - 0.020059, - 0.040244, - 0.019972, - 0.055271, - -0.122542, - -0.021821, - -0.04034, - -0.036825, - 0.011734, - 0.064097, - 0.137938, - -0.051385, - -0.05444 + 0.071718, + -0.008819, + -0.054672, + -0.015432, + -0.030976, + -0.0758, + -0.008265, + -0.014497, + 0.096481, + -0.090083, + 0.010936, + 0.057455, + 0.004509, + 0.009555, + 0.015099, + 0.124912, + -0.001339, + -0.200161, + 0.011805, + -0.021756, + 0.042494, + -0.027702, + -0.006524, + -0.197164, + 0.016178, + -0.059881, + -0.185588, + -0.020978, + -0.041852, + 0.061387, + 0.020118, + 0.027282, + 0.12091, + -0.049469, + -0.028752, + 0.231728, + 0.036168, + 0.011999, + 0.008939, + -0.007228, + 0.002977, + -0.033564, + 0.010024, + -0.00966, + -0.044596, + -0.043678, + 0.019131, + 0.090613, + 0.04426, + 0.087199, + -0.131077, + -0.06443, + 0.011578, + -0.033969, + 0.059241, + 0.021002, + 0.079187, + -0.06259, + -0.005068, + 0.004954, + -0.010163, + 0.005719, + -0.037729, + -0.041705, + 0.004209, + -0.040269, + 0.004894, + 0.001695, + 0.051296, + -0.010001, + 0.012828, + -0.088202, + -0.003967, + -0.006604, + -0.049106, + -0.063331, + 0.012861, + -0.105234, + 0.019675, + 0.024241, + 0.211199, + -0.078568, + -0.030876, + 0.122076, + 0.022054, + -0.004784, + 0.047175, + -0.000978, + 0.032414, + -0.142987, + 0.053993, + -0.00592, + -0.049454, + -0.00449, + 0.015489, + 0.028956, + 0.070892, + 0.008697, + -0.089013, + -0.000696, + -0.039603, + -0.194077, + -0.012834, + -0.063908, + 0.149661, + -0.10558, + 0.018135, + 0.135092, + 0.007163, + 0.006242, + 0.044593, + -0.006535, + -0.001669, + -0.236749, + 0.05098, + 0.000486, + 0.114364, + 0.000405, + 0.011635, + -0.094436, + 0.031127, + -0.022272, + -0.079185, + 0.000593, + -0.005661, + 0.010237, + 0.053563, + -0.031454, + 0.180309, + -0.047137, + 0.059878, + 0.179391, + 0.031428, + 0.017074, + -0.030701, + -0.005562, + 0.000418, + -0.012365, + 0.013679, + -0.033032, + -0.00381, + -0.005151, + 0.024023, + 0.081194, + 0.07761, + -0.015196, + -0.133154, + -0.065255, + 0.03357, + -0.140788, + 0.013105, + -0.006519, + 0.204232, + -0.024026, + -0.023929, + 0.033823, + 0.044788, + 0.043984, + -0.029424, + -0.060313, + -0.008281, + -0.092494, + 0.004592, + -0.003231, + 0.018919, + -0.024515, + 0.006924, + 0.000745, + 0.0061, + -0.001543, + -0.011302, + -0.008656, + -0.013022, + -0.033043, + -0.041233, + 0.017999, + 0.258595, + -0.017567, + -0.024197, + 0.083855, + 0.051797, + 0.004024, + 0.071533, + 0.03116, + 0.007688, + -0.254467, + 0.042539, + -0.020792, + 0.026787, + -0.049473, + 0.026456, + 0.030912, + 0.195842, + 0.005242, + -0.082503, + 0.01499, + -0.003618, + 0.049112, + -0.051307, + 0.011834, + -0.019008, + -0.200098, + -0.059657, + 0.109592, + 0.006945, + 0.023641, + 0.001411, + 0.114409, + -0.020787, + -0.089155, + 0.010246, + 0.027716, + -0.023129, + 0.062988, + -0.05887, + 0.103139, + 0.085568, + -0.054059, + -0.003828, + -0.088452, + -0.091657, + 0.042975, + -0.00084, + -0.087786, + -0.039477, + -0.11335, + -0.084967, + 0.047143, + 0.087936, + -0.011047, + -0.048831, + -0.006249, + -0.016875, + 0.011941, + 0.05381, + -0.022219, + -0.054344, + -0.08878, + 0.052333, + -0.000392, + 0.105344, + 0.099578, + -0.087181, + 0.012334, + -0.03541, + 0.05933, + -0.098218, + 0.011336, + -0.095554, + -0.165198, + -0.011166, + 0.064269, + 0.007946, + 0.00755, + 0.037587, + -0.042181, + 0.006968, + 0.070807, + -0.011778, + 0.011303, + -0.019473, + 0.047049, + -0.04503, + 0.083796, + -0.009682, + 0.013804, + -0.010193, + 0.036569, + 0.060744, + 0.058283, + -0.054226, + 0.013443, + -0.077145, + -0.041329, + -0.077576, + 0.153684, + -0.017517, + -0.011849, + -0.058648, + 0.061664, + 0.020648, + 0.028756, + 0.181853, + -0.026616, + -0.008608, + -0.032139, + 0.034001, + 0.020492, + 0.168679, + 0.071058, + -0.100804, + 0.103743, + 0.043606, + 0.088188, + -0.02689, + 0.016334, + -0.039233, + -0.162523, + 0.075108, + 0.110318, + 0.007568, + -0.016935, + 0.014621, + 0.160262, + 0.036108, + 0.163532, + -0.054512, + 0.065763, + -0.064999, + 0.047337, + -0.044309, + 0.000516, + 0.092965, + -0.036485, + -0.002841, + -0.013774, + -0.010288, + 0.02474, + -0.133301, + -0.062872, + -0.13546, + -0.094675, + 0.09341, + -0.008637, + 0.10444, + 0.035703, + -0.036872, + -0.014402, + -4.3e-05, + -0.017422, + 0.045839, + -0.058935, + -0.044966, + -0.045974, + 0.000507, + -0.055395, + 0.132301, + -0.081356, + -0.094584, + 0.101946, + 0.059299, + 0.144526, + -0.186208, + 0.078314, + -0.144836, + -0.101824, + -0.016033, + -0.008788, + 0.094889, + 0.061311, + -0.012358, + 0.075019, + -0.028781, + 0.138916, + -0.000119, + -0.004287, + 0.002651, + -0.053312, + 0.007765, + 0.052629, + 0.025514, + 0.002528, + -0.000727, + -0.015146, + 0.001421, + 0.066357, + -0.166622, + 0.046622, + -0.096597, + -0.078581, + -0.026191, + -0.020059, + -0.040244, + -0.019972, + -0.055271, + 0.122542, + 0.021821, + 0.04034, + 0.036825, + -0.011734, + -0.064097, + -0.137938, + 0.051385, + 0.05444 ], "eigen_values": [ 0.0,