-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathHyper.hpp
More file actions
97 lines (71 loc) · 3.7 KB
/
Hyper.hpp
File metadata and controls
97 lines (71 loc) · 3.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#ifndef HYPER_HPP
#define HYPER_HPP
namespace compass {
class HyperSVD : public AlgebraicFit<HyperSVD> {
friend class AlgebraicFit<HyperSVD>;
public:
HyperSVD() : AlgebraicFit<HyperSVD>() {}
HyperSVD(const Eigen::Ref<const DataMatrixD>& data) : AlgebraicFit<HyperSVD>(data) {}
protected:
HyperSVD& compute (const Eigen::Ref<const DataMatrixD>& data) {
Eigen::MatrixX<double> centered = (Eigen::MatrixX<double>(data.rows(), data.cols())
<< data.rowwise() - mean).finished();
Eigen::VectorX<double> Z = (centered.array().square()).rowwise().sum();
ExtendedDesignMatrix mat = (ExtendedDesignMatrix(centered.rows(), 4)
<< Z, centered, Eigen::VectorXd::Ones(centered.rows())).finished();
Eigen::BDCSVD<Eigen::MatrixXd> SVD{mat, Eigen::ComputeThinV};
Eigen::MatrixX<double> V = SVD.matrixV();
Eigen::MatrixX<double> S = SVD.singularValues();
Eigen::VectorXd solution;
if (S.minCoeff() < 1e-12) {
solution = V.col(3);
} else {
Eigen::RowVector4<double> R = mat.colwise().mean();
clamp(R);
Eigen::MatrixX<double> W = V * S.asDiagonal() * V.transpose();
Eigen::MatrixX<double> N = (Eigen::Matrix4<double>(4, 4)
<< 8*R(0), 4*R(1), 4*R(2), 2, 4*R(1), 1, 0, 0, 4*R(2), 0, 1, 0, 2, 0, 0, 0).finished();
Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> solver;
solver.compute(W * N.inverse() * W);
Eigen::MatrixXd eigenvectors = solver.eigenvectors();
Eigen::Vector4d AStar = eigenvectors.col(1);
Eigen::LDLT<Eigen::MatrixXd> cholesky = W.ldlt();
solution = cholesky.solve(AStar);
}
AlgebraicFit::computeCircleParameters(solution);
return *this;
}
};
class HyperSimple : public AlgebraicFit<HyperSimple> {
friend class AlgebraicFit<HyperSimple>;
public:
HyperSimple() : AlgebraicFit<HyperSimple>() {}
HyperSimple(const Eigen::Ref<const DataMatrixD>& data) : AlgebraicFit<HyperSimple>(data) {}
protected:
HyperSimple& compute (const Eigen::Ref<const DataMatrixD>& data) {
Eigen::MatrixX<double> centered = data;
Eigen::VectorX<double> Z = (centered.array().square()).rowwise().sum();
ExtendedDesignMatrix mat = (ExtendedDesignMatrix(centered.rows(), 4)
<< Z, centered, Eigen::VectorXd::Ones(centered.rows())).finished();
Eigen::RowVectorX<double> S = mat.colwise().mean();
Eigen::MatrixX<double> M = mat.transpose() * mat;
Eigen::Matrix4<double> N = (Eigen::Matrix4<double>(4, 4)
<< 8*S(0), 4*S(1), 4*S(2), 2, 4*S(1), 1, 0, 0, 4*S(2), 0, 1, 0, 2, 0, 0, 0).finished();
Eigen::MatrixX<double> NM = N.inverse() * M;
Eigen::EigenSolver<Eigen::MatrixXd> solver;
solver.compute(NM);
Eigen::MatrixXd eigenvectors = solver.eigenvectors().real();
Eigen::VectorXd eigenvalues = solver.eigenvalues().real();
// throw an exception and cancel execution
if (eigenvalues(0) > 0) {
std::cout << "Error, the smallest eigenvalue is positive" << std::endl;
} else if (eigenvalues(1) < 0) {
std::cout << "Error, the second smallest eigenvalue is negative" << std::endl;
}
Eigen::Vector4d AStar = eigenvectors.col(eigenvectors.cols() - 1);
AlgebraicFit::computeCircleParameters(AStar, false);
return *this;
}
};
}
#endif /* HYPER_HPP */