philsupertramp/game-math
Loading...
Searching...
No Matches
numerics/lin_alg/TestSVD.cpp

This is an example on how to use the svd method.

#include "../../Test.h"
class SVDTestCase : public Test
{
bool TestSVDDimensions() {
Matrix<double> A = { { 1, 1, 1, 1 }, { 1, 3, 1, 2 } };
auto result = svd(A.Transpose(), 0);
auto U = result[0];
auto S = eye(U.rows(), U.columns());
S(0, 0) = result[1](0, 0);
S(1, 1) = result[1](0, 1);
auto VH = result[2];
// A stays A
AssertEqual((U.Transpose() * S) * VH, A);
return true;
}
bool TestSVD() {
Matrix<double> A = { { 1, 1, 1, 1 }, { 1, 3, 1, 2 } };
auto result = svd(A, 0);
auto U = result[0];
auto S = eye(U.rows(), U.columns());
S(0, 0) = result[1](0, 0);
S(1, 1) = result[1](0, 1);
auto VH = result[2];
// A stays A
AssertEqual(U * S * VH, A);
return true;
}
bool TestPCANormalDistribution() {
// Create in (2, 1) centered normal distributed data.
size_t n_points = 1000;
auto random_data = Matrix<double>::Normal(n_points, 2, 0, 0.1).Transpose();
Matrix<double> xC = { { 2 }, { 1 } }; // center (mean)
Matrix<double> sig = { { 2 }, { 0.5 } }; // principal axes
// Rotate data
auto theta = M_PI / 3.0;
// Transformation matrix for rotation
Matrix<double> R = { { cos(theta), -sin(theta) }, { sin(theta), cos(theta) } };
// Transform normal distributed data
auto X = (R * diag(sig) * random_data + diag(xC) * ones(2, n_points));
// 1. compute mean row
Matrix<double> row_mean(0.0, 1, X.rows());
for(size_t i = 0; i < X.rows(); ++i) { row_mean(0, i) = mean(X.GetSlice(i, i, 0, X.columns() - 1), -1)(0, 0); }
Matrix<double> X_bar = (Matrix<double>(1.0, X.columns(), 1) * row_mean).Transpose();
// 2. B = X - X'
auto B = X - X_bar;
B = 1.0 / (double)sqrt(static_cast<double>(X.rows())) * B;
// find principal components
auto SVD = svd(B, 0);
auto U = SVD[0].Transpose();
auto S = SVD[1];
auto VT = SVD[2];
Matrix<double> Theta = 2.0 * M_PI * linspace(0, 1, 100).Transpose();
auto newTheta =
HorizontalConcat(Theta.Apply([](double val) { return cos(val); }), Theta.Apply([](double val) { return sin(val); }))
.Transpose();
auto xStd = U * diag(S) * newTheta;
#if USE_VIS
Plot plot1("PCA Example");
plot1.AddData(random_data.Transpose(), "Data", DOTS);
plot1();
plot1.AddData(X.Transpose(), "Data", DOTS);
plot1();
Plot plot("PCA Example");
plot.AddData(X.Transpose(), "Data", DOTS);
auto mean1 = row_mean(0, 0);
auto mean2 = row_mean(0, 1);
// 1-a confidence interval
plot.AddData(
xStd.GetSlice(0, 0, 0, xStd.columns() - 1).Apply([mean1](double v) { return mean1 + v; }).Transpose(),
xStd.GetSlice(1, 1, 0, xStd.columns() - 1).Apply([mean2](double v) { return mean2 + v; }).Transpose(),
"conf 1",
LINE);
plot.AddData(
xStd.GetSlice(0, 0, 0, xStd.columns() - 1).Apply([mean1](double v) { return mean1 + 2.0 * v; }).Transpose(),
xStd.GetSlice(1, 1, 0, xStd.columns() - 1).Apply([mean2](double v) { return mean2 + 2.0 * v; }).Transpose(),
"conf 2",
LINE);
plot.AddData(
xStd.GetSlice(0, 0, 0, xStd.columns() - 1).Apply([mean1](double v) { return mean1 + 3.0 * v; }).Transpose(),
xStd.GetSlice(1, 1, 0, xStd.columns() - 1).Apply([mean2](double v) { return mean2 + 3.0 * v; }).Transpose(),
"conf 3",
LINE);
std::cout << "S:\n" << S << std::endl;
{ mean1, mean2 },
{ mean1 + U(0, 0) * S(0, 0), mean2 + U(1, 0) * S(0, 0) },
};
std::cout << "PC1:\n" << pc1 << std::endl;
plot.AddData(pc1, "pc 1", LINE);
Matrix<double> pc2 = { { mean1, mean2 }, { mean1 + U(0, 1) * S(0, 1), mean2 + U(1, 1) * S(0, 1) } };
std::cout << "PC2:\n" << pc2 << std::endl;
plot.AddData(pc2, "pc 2", LINE);
plot();
#endif
return true;
}
public:
void run() override {
TestSVD();
//TestSVDDimensions();
TestPCANormalDistribution();
}
};
int main() {
SVDTestCase().run();
return 0;
}
@ DOTS
Creates dot data.
Definition: Plot.h:16
@ LINE
Creates line data.
Definition: Plot.h:14
Definition: Matrix.h:42
constexpr Matrix< T > Transpose() const
Definition: Matrix.h:256
static Matrix Normal(size_t rows, size_t columns, double mu, double sigma)
Definition: Matrix.h:171
Matrix< T > Apply(const std::function< T(T)> &fun) const
Definition: Matrix.h:375
Definition: Plot.h:104
void AddData(const Matrix< double > &x, const Matrix< double > &y, const std::string &name, DataTypes dataType=DataTypes::NONE, const char *character=nullptr)
Definition: Plot.h:182
Matrix< T > HorizontalConcat(const Matrix< T > &lhs, const Matrix< T > &rhs)
Definition: matrix_utils.h:81
Matrix< T > mean(const Matrix< T > &mat, int axis=-1)
Definition: matrix_utils.h:401
Matrix< T > diag(const Matrix< T > &in)
Definition: utils.h:135
Matrix< double > eye(size_t rows, size_t columns=0)
Matrix< double > ones(size_t rows, size_t columns=1, size_t elements=1)
Matrix< double > linspace(double start, double end, unsigned long num_elements)
std::vector< Matrix< double > > svd(const Matrix< double > &A, const size_t &k, const double epsilon=0.1e-4)
Definition: svd.h:14