80 const int nCh =
static_cast<int>(matData.rows());
81 const int nSamples =
static_cast<int>(matData.cols());
83 if (nComponents <= 0 || nComponents > nCh)
86 if (nCh < 2 || nSamples < 2) {
87 qWarning() <<
"[PicardIca::run] Insufficient data dimensions.";
92 result.
vecMean = matData.rowwise().mean();
93 MatrixXd
X = matData.colwise() - result.
vecMean;
96 MatrixXd cov = (
X *
X.transpose()) /
static_cast<double>(nSamples - 1);
97 SelfAdjointEigenSolver<MatrixXd> eig(cov);
98 if (eig.info() != Success) {
99 qWarning() <<
"[PicardIca::run] Eigendecomposition failed.";
104 VectorXd eigenvalues = eig.eigenvalues().reverse();
105 MatrixXd eigenvectors = eig.eigenvectors().rowwise().reverse();
108 VectorXd D = eigenvalues.head(nComponents);
109 MatrixXd V = eigenvectors.leftCols(nComponents);
112 VectorXd Dinvsqrt = D.array().max(1e-15).sqrt().inverse().matrix();
113 MatrixXd K = Dinvsqrt.asDiagonal() * V.transpose();
114 MatrixXd Kinv = V * D.array().sqrt().matrix().asDiagonal();
119 std::mt19937 gen(
static_cast<unsigned>(randomSeed));
120 std::normal_distribution<double> dist(0.0, 1.0);
122 MatrixXd W(nComponents, nComponents);
123 for (
int i = 0; i < nComponents; ++i)
124 for (
int j = 0; j < nComponents; ++j)
128 HouseholderQR<MatrixXd> qr(W);
129 W = qr.householderQ() * MatrixXd::Identity(nComponents, nComponents);
135 for (
int iter = 0; iter < maxIter; ++iter) {
136 MatrixXd Wnew(nComponents, nComponents);
138 for (
int k = 0; k < nComponents; ++k) {
140 VectorXd yk = (W.row(k) * Xw).transpose();
145 logcoshNonlinearity(yk, gk, gPrimeMean, nSamples);
149 VectorXd wNew = (Xw * gk /
static_cast<double>(nSamples))
150 - gPrimeMean * W.row(k).transpose();
152 Wnew.row(k) = wNew.transpose();
156 SelfAdjointEigenSolver<MatrixXd> eigW(Wnew * Wnew.transpose());
157 MatrixXd sqrtInv = eigW.eigenvectors()
158 * eigW.eigenvalues().array().max(1e-15).rsqrt().matrix().asDiagonal()
159 * eigW.eigenvectors().transpose();
160 Wnew = sqrtInv * Wnew;
163 double maxChange = 0.0;
164 for (
int k = 0; k < nComponents; ++k) {
165 double dot = std::abs(Wnew.row(k).dot(W.row(k)));
166 dot = std::min(dot, 1.0);
167 maxChange = std::max(maxChange, 1.0 - dot);
172 if (maxChange < tol) {
static IcaResult run(const Eigen::MatrixXd &matData, int nComponents=-1, int maxIter=200, double tol=1e-7, int lbfgsMemory=7, int randomSeed=42)