You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

190 lines
4.9 KiB

  1. // This file is part of Eigen, a lightweight C++ template library
  2. // for linear algebra.
  3. //
  4. // Copyright (C) 2012 Desire Nuentsa <desire.nuentsa_wakam@inria.fr>
  5. // Copyright (C) 2012 Gael Guennebaud <gael.guennebaud@inria.fr>
  6. //
  7. // This Source Code Form is subject to the terms of the Mozilla
  8. // Public License v. 2.0. If a copy of the MPL was not distributed
  9. // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
  10. #include <iostream>
  11. #include <fstream>
  12. #include <iomanip>
  13. #include "main.h"
  14. #include <Eigen/LevenbergMarquardt>
  15. using namespace std;
  16. using namespace StormEigen;
  17. template<typename Scalar>
  18. struct DenseLM : DenseFunctor<Scalar>
  19. {
  20. typedef DenseFunctor<Scalar> Base;
  21. typedef typename Base::JacobianType JacobianType;
  22. typedef Matrix<Scalar,Dynamic,1> VectorType;
  23. DenseLM(int n, int m) : DenseFunctor<Scalar>(n,m)
  24. { }
  25. VectorType model(const VectorType& uv, VectorType& x)
  26. {
  27. VectorType y; // Should change to use expression template
  28. int m = Base::values();
  29. int n = Base::inputs();
  30. eigen_assert(uv.size()%2 == 0);
  31. eigen_assert(uv.size() == n);
  32. eigen_assert(x.size() == m);
  33. y.setZero(m);
  34. int half = n/2;
  35. VectorBlock<const VectorType> u(uv, 0, half);
  36. VectorBlock<const VectorType> v(uv, half, half);
  37. for (int j = 0; j < m; j++)
  38. {
  39. for (int i = 0; i < half; i++)
  40. y(j) += u(i)*std::exp(-(x(j)-i)*(x(j)-i)/(v(i)*v(i)));
  41. }
  42. return y;
  43. }
  44. void initPoints(VectorType& uv_ref, VectorType& x)
  45. {
  46. m_x = x;
  47. m_y = this->model(uv_ref, x);
  48. }
  49. int operator()(const VectorType& uv, VectorType& fvec)
  50. {
  51. int m = Base::values();
  52. int n = Base::inputs();
  53. eigen_assert(uv.size()%2 == 0);
  54. eigen_assert(uv.size() == n);
  55. eigen_assert(fvec.size() == m);
  56. int half = n/2;
  57. VectorBlock<const VectorType> u(uv, 0, half);
  58. VectorBlock<const VectorType> v(uv, half, half);
  59. for (int j = 0; j < m; j++)
  60. {
  61. fvec(j) = m_y(j);
  62. for (int i = 0; i < half; i++)
  63. {
  64. fvec(j) -= u(i) *std::exp(-(m_x(j)-i)*(m_x(j)-i)/(v(i)*v(i)));
  65. }
  66. }
  67. return 0;
  68. }
  69. int df(const VectorType& uv, JacobianType& fjac)
  70. {
  71. int m = Base::values();
  72. int n = Base::inputs();
  73. eigen_assert(n == uv.size());
  74. eigen_assert(fjac.rows() == m);
  75. eigen_assert(fjac.cols() == n);
  76. int half = n/2;
  77. VectorBlock<const VectorType> u(uv, 0, half);
  78. VectorBlock<const VectorType> v(uv, half, half);
  79. for (int j = 0; j < m; j++)
  80. {
  81. for (int i = 0; i < half; i++)
  82. {
  83. fjac.coeffRef(j,i) = -std::exp(-(m_x(j)-i)*(m_x(j)-i)/(v(i)*v(i)));
  84. fjac.coeffRef(j,i+half) = -2.*u(i)*(m_x(j)-i)*(m_x(j)-i)/(std::pow(v(i),3)) * std::exp(-(m_x(j)-i)*(m_x(j)-i)/(v(i)*v(i)));
  85. }
  86. }
  87. return 0;
  88. }
  89. VectorType m_x, m_y; //Data Points
  90. };
  91. template<typename FunctorType, typename VectorType>
  92. int test_minimizeLM(FunctorType& functor, VectorType& uv)
  93. {
  94. LevenbergMarquardt<FunctorType> lm(functor);
  95. LevenbergMarquardtSpace::Status info;
  96. info = lm.minimize(uv);
  97. VERIFY_IS_EQUAL(info, 1);
  98. //FIXME Check other parameters
  99. return info;
  100. }
  101. template<typename FunctorType, typename VectorType>
  102. int test_lmder(FunctorType& functor, VectorType& uv)
  103. {
  104. typedef typename VectorType::Scalar Scalar;
  105. LevenbergMarquardtSpace::Status info;
  106. LevenbergMarquardt<FunctorType> lm(functor);
  107. info = lm.lmder1(uv);
  108. VERIFY_IS_EQUAL(info, 1);
  109. //FIXME Check other parameters
  110. return info;
  111. }
  112. template<typename FunctorType, typename VectorType>
  113. int test_minimizeSteps(FunctorType& functor, VectorType& uv)
  114. {
  115. LevenbergMarquardtSpace::Status info;
  116. LevenbergMarquardt<FunctorType> lm(functor);
  117. info = lm.minimizeInit(uv);
  118. if (info==LevenbergMarquardtSpace::ImproperInputParameters)
  119. return info;
  120. do
  121. {
  122. info = lm.minimizeOneStep(uv);
  123. } while (info==LevenbergMarquardtSpace::Running);
  124. VERIFY_IS_EQUAL(info, 1);
  125. //FIXME Check other parameters
  126. return info;
  127. }
  128. template<typename T>
  129. void test_denseLM_T()
  130. {
  131. typedef Matrix<T,Dynamic,1> VectorType;
  132. int inputs = 10;
  133. int values = 1000;
  134. DenseLM<T> dense_gaussian(inputs, values);
  135. VectorType uv(inputs),uv_ref(inputs);
  136. VectorType x(values);
  137. // Generate the reference solution
  138. uv_ref << -2, 1, 4 ,8, 6, 1.8, 1.2, 1.1, 1.9 , 3;
  139. //Generate the reference data points
  140. x.setRandom();
  141. x = 10*x;
  142. x.array() += 10;
  143. dense_gaussian.initPoints(uv_ref, x);
  144. // Generate the initial parameters
  145. VectorBlock<VectorType> u(uv, 0, inputs/2);
  146. VectorBlock<VectorType> v(uv, inputs/2, inputs/2);
  147. // Solve the optimization problem
  148. //Solve in one go
  149. u.setOnes(); v.setOnes();
  150. test_minimizeLM(dense_gaussian, uv);
  151. //Solve until the machine precision
  152. u.setOnes(); v.setOnes();
  153. test_lmder(dense_gaussian, uv);
  154. // Solve step by step
  155. v.setOnes(); u.setOnes();
  156. test_minimizeSteps(dense_gaussian, uv);
  157. }
  158. void test_denseLM()
  159. {
  160. CALL_SUBTEST_2(test_denseLM_T<double>());
  161. // CALL_SUBTEST_2(test_sparseLM_T<std::complex<double>());
  162. }