Skip to content

Commit 28bfe2d

Browse files
authored
Merge pull request #2525 from SCIInstitute/pca_loadings_for_morphodev
Add coefficient extraction and variance-ratio controls to MorphologicalDeviationSc
2 parents 687bdac + 94d25fa commit 28bfe2d

3 files changed

Lines changed: 75 additions & 0 deletions

File tree

Libs/Optimize/Function/EarlyStop/MorphologicalDeviationScore.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,32 @@ Eigen::VectorXd MorphologicalDeviationScore::GetMorphoDevScore(const Eigen::Matr
110110
}
111111
}
112112

113+
//---------------------------------------------------------------------------
114+
Eigen::MatrixXd MorphologicalDeviationScore::GetPCACoefficients(const Eigen::MatrixXd& X) {
115+
try {
116+
if (!is_fitted_) {
117+
throw std::runtime_error("PPCA model is not fitted on control shapes.");
118+
}
119+
120+
if (all_components_.cols() == 0) {
121+
throw std::runtime_error("PPCA basis is empty.");
122+
}
123+
124+
if (X.cols() != mean_.cols()) {
125+
throw std::runtime_error("Input feature dimension does not match fitted PPCA model.");
126+
}
127+
128+
if (X.rows() == 0) {
129+
return Eigen::MatrixXd(0, all_components_.cols());
130+
}
131+
132+
Eigen::MatrixXd X_bar = X.rowwise() - mean_; // (n x d)
133+
return X_bar * all_components_; // (n x rank) scores in PCA basis
134+
135+
} catch (std::exception& e) {
136+
SW_ERROR("Exception in computing PCA coefficients for early stopping {}", e.what());
137+
return Eigen::MatrixXd();
138+
}
139+
}
140+
113141
} // namespace shapeworks

Libs/Optimize/Function/EarlyStop/MorphologicalDeviationScore.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include <Eigen/Dense>
4+
#include <stdexcept>
45

56
namespace shapeworks {
67
class MorphologicalDeviationScore {
@@ -11,6 +12,14 @@ class MorphologicalDeviationScore {
1112
/// Get Mahalanobis-based deviation score for test samples (non-fixed
1213
/// shapes/domains)
1314
Eigen::VectorXd GetMorphoDevScore(const Eigen::MatrixXd& X); // (n,)
15+
Eigen::MatrixXd GetPCACoefficients(const Eigen::MatrixXd& X); // (n, rank)
16+
void SetRetainedVarianceRatio(double ratio) {
17+
if (ratio <= 0.0 || ratio > 1.0) {
18+
throw std::invalid_argument("retained_variance_ratio must be in the interval (0, 1].");
19+
}
20+
retained_variance_ratio_ = ratio;
21+
}
22+
double GetRetainedVarianceRatio() const { return retained_variance_ratio_; }
1423

1524
private:
1625
/// Flag to ensure control shapes are set and PCA model is in place

Libs/Python/ShapeworksPython.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1744,6 +1744,28 @@ PYBIND11_MODULE(shapeworks_py, m) {
17441744
True if fitting was successful, False otherwise.
17451745
)pbdoc")
17461746

1747+
.def("SetRetainedVarianceRatio",
1748+
&MorphologicalDeviationScore::SetRetainedVarianceRatio, py::arg("ratio"),
1749+
R"pbdoc(
1750+
Set the retained variance ratio used to choose PPCA components.
1751+
1752+
Parameters
1753+
----------
1754+
ratio : float
1755+
Target cumulative variance ratio in the interval (0, 1].
1756+
)pbdoc")
1757+
1758+
.def("GetRetainedVarianceRatio",
1759+
&MorphologicalDeviationScore::GetRetainedVarianceRatio,
1760+
R"pbdoc(
1761+
Get the retained variance ratio used to choose PPCA components.
1762+
1763+
Returns
1764+
-------
1765+
float
1766+
The current retained variance ratio.
1767+
)pbdoc")
1768+
17471769
.def("GetMorphoDevScore",
17481770
&MorphologicalDeviationScore::GetMorphoDevScore, py::arg("X"),
17491771
R"pbdoc(
@@ -1758,5 +1780,21 @@ PYBIND11_MODULE(shapeworks_py, m) {
17581780
-------
17591781
numpy.ndarray
17601782
Vector of Mahalanobis distances for each sample.
1783+
)pbdoc")
1784+
1785+
.def("GetPCACoefficients",
1786+
&MorphologicalDeviationScore::GetPCACoefficients, py::arg("X"),
1787+
R"pbdoc(
1788+
Project samples onto the fitted PCA basis.
1789+
1790+
Parameters
1791+
----------
1792+
X : numpy.ndarray
1793+
Matrix of samples (n_samples x n_features)
1794+
1795+
Returns
1796+
-------
1797+
numpy.ndarray
1798+
Matrix of PCA coefficients with shape (n_samples, rank).
17611799
)pbdoc");
17621800
} // PYBIND11_MODULE(shapeworks_py)

0 commit comments

Comments
 (0)