| // This file is part of Eigen, a lightweight C++ template library |
| // for linear algebra. Eigen itself is part of the KDE project. |
| // |
| // Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com> |
| // |
| // This Source Code Form is subject to the terms of the Mozilla |
| // Public License v. 2.0. If a copy of the MPL was not distributed |
| // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. |
| |
| #include "main.h" |
| #include <Eigen/LeastSquares> |
| |
| template<typename VectorType, |
| typename HyperplaneType> |
| void makeNoisyCohyperplanarPoints(int numPoints, |
| VectorType **points, |
| HyperplaneType *hyperplane, |
| typename VectorType::Scalar noiseAmplitude) |
| { |
| typedef typename VectorType::Scalar Scalar; |
| const int size = points[0]->size(); |
| // pick a random hyperplane, store the coefficients of its equation |
| hyperplane->coeffs().resize(size + 1); |
| for(int j = 0; j < size + 1; j++) |
| { |
| do { |
| hyperplane->coeffs().coeffRef(j) = ei_random<Scalar>(); |
| } while(ei_abs(hyperplane->coeffs().coeff(j)) < 0.5); |
| } |
| |
| // now pick numPoints random points on this hyperplane |
| for(int i = 0; i < numPoints; i++) |
| { |
| VectorType& cur_point = *(points[i]); |
| do |
| { |
| cur_point = VectorType::Random(size)/*.normalized()*/; |
| // project cur_point onto the hyperplane |
| Scalar x = - (hyperplane->coeffs().start(size).cwise()*cur_point).sum(); |
| cur_point *= hyperplane->coeffs().coeff(size) / x; |
| } while( cur_point.norm() < 0.5 |
| || cur_point.norm() > 2.0 ); |
| } |
| |
| // add some noise to these points |
| for(int i = 0; i < numPoints; i++ ) |
| *(points[i]) += noiseAmplitude * VectorType::Random(size); |
| } |
| |
| template<typename VectorType> |
| void check_linearRegression(int numPoints, |
| VectorType **points, |
| const VectorType& original, |
| typename VectorType::Scalar tolerance) |
| { |
| int size = points[0]->size(); |
| assert(size==2); |
| VectorType result(size); |
| linearRegression(numPoints, points, &result, 1); |
| typename VectorType::Scalar error = (result - original).norm() / original.norm(); |
| VERIFY(ei_abs(error) < ei_abs(tolerance)); |
| } |
| |
| template<typename VectorType, |
| typename HyperplaneType> |
| void check_fitHyperplane(int numPoints, |
| VectorType **points, |
| const HyperplaneType& original, |
| typename VectorType::Scalar tolerance) |
| { |
| int size = points[0]->size(); |
| HyperplaneType result(size); |
| fitHyperplane(numPoints, points, &result); |
| result.coeffs() *= original.coeffs().coeff(size)/result.coeffs().coeff(size); |
| typename VectorType::Scalar error = (result.coeffs() - original.coeffs()).norm() / original.coeffs().norm(); |
| std::cout << ei_abs(error) << " xxx " << ei_abs(tolerance) << std::endl; |
| VERIFY(ei_abs(error) < ei_abs(tolerance)); |
| } |
| |
| void test_eigen2_regression() |
| { |
| for(int i = 0; i < g_repeat; i++) |
| { |
| #ifdef EIGEN_TEST_PART_1 |
| { |
| Vector2f points2f [1000]; |
| Vector2f *points2f_ptrs [1000]; |
| for(int i = 0; i < 1000; i++) points2f_ptrs[i] = &(points2f[i]); |
| Vector2f coeffs2f; |
| Hyperplane<float,2> coeffs3f; |
| makeNoisyCohyperplanarPoints(1000, points2f_ptrs, &coeffs3f, 0.01f); |
| coeffs2f[0] = -coeffs3f.coeffs()[0]/coeffs3f.coeffs()[1]; |
| coeffs2f[1] = -coeffs3f.coeffs()[2]/coeffs3f.coeffs()[1]; |
| CALL_SUBTEST(check_linearRegression(10, points2f_ptrs, coeffs2f, 0.05f)); |
| CALL_SUBTEST(check_linearRegression(100, points2f_ptrs, coeffs2f, 0.01f)); |
| CALL_SUBTEST(check_linearRegression(1000, points2f_ptrs, coeffs2f, 0.002f)); |
| } |
| #endif |
| #ifdef EIGEN_TEST_PART_2 |
| { |
| Vector2f points2f [1000]; |
| Vector2f *points2f_ptrs [1000]; |
| for(int i = 0; i < 1000; i++) points2f_ptrs[i] = &(points2f[i]); |
| Hyperplane<float,2> coeffs3f; |
| makeNoisyCohyperplanarPoints(1000, points2f_ptrs, &coeffs3f, 0.01f); |
| CALL_SUBTEST(check_fitHyperplane(10, points2f_ptrs, coeffs3f, 0.05f)); |
| CALL_SUBTEST(check_fitHyperplane(100, points2f_ptrs, coeffs3f, 0.01f)); |
| CALL_SUBTEST(check_fitHyperplane(1000, points2f_ptrs, coeffs3f, 0.002f)); |
| } |
| #endif |
| #ifdef EIGEN_TEST_PART_3 |
| { |
| Vector4d points4d [1000]; |
| Vector4d *points4d_ptrs [1000]; |
| for(int i = 0; i < 1000; i++) points4d_ptrs[i] = &(points4d[i]); |
| Hyperplane<double,4> coeffs5d; |
| makeNoisyCohyperplanarPoints(1000, points4d_ptrs, &coeffs5d, 0.01); |
| CALL_SUBTEST(check_fitHyperplane(10, points4d_ptrs, coeffs5d, 0.05)); |
| CALL_SUBTEST(check_fitHyperplane(100, points4d_ptrs, coeffs5d, 0.01)); |
| CALL_SUBTEST(check_fitHyperplane(1000, points4d_ptrs, coeffs5d, 0.002)); |
| } |
| #endif |
| #ifdef EIGEN_TEST_PART_4 |
| { |
| VectorXcd *points11cd_ptrs[1000]; |
| for(int i = 0; i < 1000; i++) points11cd_ptrs[i] = new VectorXcd(11); |
| Hyperplane<std::complex<double>,Dynamic> *coeffs12cd = new Hyperplane<std::complex<double>,Dynamic>(11); |
| makeNoisyCohyperplanarPoints(1000, points11cd_ptrs, coeffs12cd, 0.01); |
| CALL_SUBTEST(check_fitHyperplane(100, points11cd_ptrs, *coeffs12cd, 0.025)); |
| CALL_SUBTEST(check_fitHyperplane(1000, points11cd_ptrs, *coeffs12cd, 0.006)); |
| delete coeffs12cd; |
| for(int i = 0; i < 1000; i++) delete points11cd_ptrs[i]; |
| } |
| #endif |
| } |
| } |