polynomialsolver.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. // This file is part of Eigen, a lightweight C++ template library
  2. // for linear algebra.
  3. //
  4. // Copyright (C) 2010 Manuel Yguel <manuel.yguel@gmail.com>
  5. //
  6. // This Source Code Form is subject to the terms of the Mozilla
  7. // Public License v. 2.0. If a copy of the MPL was not distributed
  8. // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
  9. #include "main.h"
  10. #include <unsupported/Eigen/Polynomials>
  11. #include <iostream>
  12. #include <algorithm>
  13. using namespace std;
  14. namespace Eigen {
  15. namespace internal {
  16. template<int Size>
  17. struct increment_if_fixed_size
  18. {
  19. enum {
  20. ret = (Size == Dynamic) ? Dynamic : Size+1
  21. };
  22. };
  23. }
  24. }
  25. template<typename PolynomialType>
  26. PolynomialType polyder(const PolynomialType& p)
  27. {
  28. typedef typename PolynomialType::Scalar Scalar;
  29. PolynomialType res(p.size());
  30. for(Index i=1; i<p.size(); ++i)
  31. res[i-1] = p[i]*Scalar(i);
  32. res[p.size()-1] = 0.;
  33. return res;
  34. }
  35. template<int Deg, typename POLYNOMIAL, typename SOLVER>
  36. bool aux_evalSolver( const POLYNOMIAL& pols, SOLVER& psolve )
  37. {
  38. typedef typename POLYNOMIAL::Scalar Scalar;
  39. typedef typename POLYNOMIAL::RealScalar RealScalar;
  40. typedef typename SOLVER::RootsType RootsType;
  41. typedef Matrix<RealScalar,Deg,1> EvalRootsType;
  42. const Index deg = pols.size()-1;
  43. // Test template constructor from coefficient vector
  44. SOLVER solve_constr (pols);
  45. psolve.compute( pols );
  46. const RootsType& roots( psolve.roots() );
  47. EvalRootsType evr( deg );
  48. POLYNOMIAL pols_der = polyder(pols);
  49. EvalRootsType der( deg );
  50. for( int i=0; i<roots.size(); ++i ){
  51. evr[i] = std::abs( poly_eval( pols, roots[i] ) );
  52. der[i] = numext::maxi(RealScalar(1.), std::abs( poly_eval( pols_der, roots[i] ) ));
  53. }
  54. // we need to divide by the magnitude of the derivative because
  55. // with a high derivative is very small error in the value of the root
  56. // yiels a very large error in the polynomial evaluation.
  57. bool evalToZero = (evr.cwiseQuotient(der)).isZero( test_precision<Scalar>() );
  58. if( !evalToZero )
  59. {
  60. cerr << "WRONG root: " << endl;
  61. cerr << "Polynomial: " << pols.transpose() << endl;
  62. cerr << "Roots found: " << roots.transpose() << endl;
  63. cerr << "Abs value of the polynomial at the roots: " << evr.transpose() << endl;
  64. cerr << endl;
  65. }
  66. std::vector<RealScalar> rootModuli( roots.size() );
  67. Map< EvalRootsType > aux( &rootModuli[0], roots.size() );
  68. aux = roots.array().abs();
  69. std::sort( rootModuli.begin(), rootModuli.end() );
  70. bool distinctModuli=true;
  71. for( size_t i=1; i<rootModuli.size() && distinctModuli; ++i )
  72. {
  73. if( internal::isApprox( rootModuli[i], rootModuli[i-1] ) ){
  74. distinctModuli = false; }
  75. }
  76. VERIFY( evalToZero || !distinctModuli );
  77. return distinctModuli;
  78. }
  79. template<int Deg, typename POLYNOMIAL>
  80. void evalSolver( const POLYNOMIAL& pols )
  81. {
  82. typedef typename POLYNOMIAL::Scalar Scalar;
  83. typedef PolynomialSolver<Scalar, Deg > PolynomialSolverType;
  84. PolynomialSolverType psolve;
  85. aux_evalSolver<Deg, POLYNOMIAL, PolynomialSolverType>( pols, psolve );
  86. }
  87. template< int Deg, typename POLYNOMIAL, typename ROOTS, typename REAL_ROOTS >
  88. void evalSolverSugarFunction( const POLYNOMIAL& pols, const ROOTS& roots, const REAL_ROOTS& real_roots )
  89. {
  90. using std::sqrt;
  91. typedef typename POLYNOMIAL::Scalar Scalar;
  92. typedef typename POLYNOMIAL::RealScalar RealScalar;
  93. typedef PolynomialSolver<Scalar, Deg > PolynomialSolverType;
  94. PolynomialSolverType psolve;
  95. if( aux_evalSolver<Deg, POLYNOMIAL, PolynomialSolverType>( pols, psolve ) )
  96. {
  97. //It is supposed that
  98. // 1) the roots found are correct
  99. // 2) the roots have distinct moduli
  100. //Test realRoots
  101. std::vector< RealScalar > calc_realRoots;
  102. psolve.realRoots( calc_realRoots, test_precision<RealScalar>());
  103. VERIFY_IS_EQUAL( calc_realRoots.size() , (size_t)real_roots.size() );
  104. const RealScalar psPrec = sqrt( test_precision<RealScalar>() );
  105. for( size_t i=0; i<calc_realRoots.size(); ++i )
  106. {
  107. bool found = false;
  108. for( size_t j=0; j<calc_realRoots.size()&& !found; ++j )
  109. {
  110. if( internal::isApprox( calc_realRoots[i], real_roots[j], psPrec ) ){
  111. found = true; }
  112. }
  113. VERIFY( found );
  114. }
  115. //Test greatestRoot
  116. VERIFY( internal::isApprox( roots.array().abs().maxCoeff(),
  117. abs( psolve.greatestRoot() ), psPrec ) );
  118. //Test smallestRoot
  119. VERIFY( internal::isApprox( roots.array().abs().minCoeff(),
  120. abs( psolve.smallestRoot() ), psPrec ) );
  121. bool hasRealRoot;
  122. //Test absGreatestRealRoot
  123. RealScalar r = psolve.absGreatestRealRoot( hasRealRoot );
  124. VERIFY( hasRealRoot == (real_roots.size() > 0 ) );
  125. if( hasRealRoot ){
  126. VERIFY( internal::isApprox( real_roots.array().abs().maxCoeff(), abs(r), psPrec ) ); }
  127. //Test absSmallestRealRoot
  128. r = psolve.absSmallestRealRoot( hasRealRoot );
  129. VERIFY( hasRealRoot == (real_roots.size() > 0 ) );
  130. if( hasRealRoot ){
  131. VERIFY( internal::isApprox( real_roots.array().abs().minCoeff(), abs( r ), psPrec ) ); }
  132. //Test greatestRealRoot
  133. r = psolve.greatestRealRoot( hasRealRoot );
  134. VERIFY( hasRealRoot == (real_roots.size() > 0 ) );
  135. if( hasRealRoot ){
  136. VERIFY( internal::isApprox( real_roots.array().maxCoeff(), r, psPrec ) ); }
  137. //Test smallestRealRoot
  138. r = psolve.smallestRealRoot( hasRealRoot );
  139. VERIFY( hasRealRoot == (real_roots.size() > 0 ) );
  140. if( hasRealRoot ){
  141. VERIFY( internal::isApprox( real_roots.array().minCoeff(), r, psPrec ) ); }
  142. }
  143. }
  144. template<typename _Scalar, int _Deg>
  145. void polynomialsolver(int deg)
  146. {
  147. typedef typename NumTraits<_Scalar>::Real RealScalar;
  148. typedef internal::increment_if_fixed_size<_Deg> Dim;
  149. typedef Matrix<_Scalar,Dim::ret,1> PolynomialType;
  150. typedef Matrix<_Scalar,_Deg,1> EvalRootsType;
  151. typedef Matrix<RealScalar,_Deg,1> RealRootsType;
  152. cout << "Standard cases" << endl;
  153. PolynomialType pols = PolynomialType::Random(deg+1);
  154. evalSolver<_Deg,PolynomialType>( pols );
  155. cout << "Hard cases" << endl;
  156. _Scalar multipleRoot = internal::random<_Scalar>();
  157. EvalRootsType allRoots = EvalRootsType::Constant(deg,multipleRoot);
  158. roots_to_monicPolynomial( allRoots, pols );
  159. evalSolver<_Deg,PolynomialType>( pols );
  160. cout << "Test sugar" << endl;
  161. RealRootsType realRoots = RealRootsType::Random(deg);
  162. roots_to_monicPolynomial( realRoots, pols );
  163. evalSolverSugarFunction<_Deg>(
  164. pols,
  165. realRoots.template cast <std::complex<RealScalar> >().eval(),
  166. realRoots );
  167. }
  168. EIGEN_DECLARE_TEST(polynomialsolver)
  169. {
  170. for(int i = 0; i < g_repeat; i++)
  171. {
  172. CALL_SUBTEST_1( (polynomialsolver<float,1>(1)) );
  173. CALL_SUBTEST_2( (polynomialsolver<double,2>(2)) );
  174. CALL_SUBTEST_3( (polynomialsolver<double,3>(3)) );
  175. CALL_SUBTEST_4( (polynomialsolver<float,4>(4)) );
  176. CALL_SUBTEST_5( (polynomialsolver<double,5>(5)) );
  177. CALL_SUBTEST_6( (polynomialsolver<float,6>(6)) );
  178. CALL_SUBTEST_7( (polynomialsolver<float,7>(7)) );
  179. CALL_SUBTEST_8( (polynomialsolver<double,8>(8)) );
  180. CALL_SUBTEST_9( (polynomialsolver<float,Dynamic>(
  181. internal::random<int>(9,13)
  182. )) );
  183. CALL_SUBTEST_10((polynomialsolver<double,Dynamic>(
  184. internal::random<int>(9,13)
  185. )) );
  186. CALL_SUBTEST_11((polynomialsolver<float,Dynamic>(1)) );
  187. CALL_SUBTEST_12((polynomialsolver<std::complex<double>,Dynamic>(internal::random<int>(2,13))) );
  188. }
  189. }