Bertini 2 - C++ Core
Software for Numerical Algebraic Geometry
Loading...
Searching...
No Matches
eigen_extensions.hpp
Go to the documentation of this file.
1//This file is part of Bertini 2.
2//
3//eigen_extensions.hpp is free software: you can redistribute it and/or modify
4//it under the terms of the GNU General Public License as published by
5//the Free Software Foundation, either version 3 of the License, or
6//(at your option) any later version.
7//
8//eigen_extensions.hpp is distributed in the hope that it will be useful,
9//but WITHOUT ANY WARRANTY; without even the implied warranty of
10//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11//GNU General Public License for more details.
12//
13//You should have received a copy of the GNU General Public License
14//along with eigen_extensions.hpp. If not, see <http://www.gnu.org/licenses/>.
15//
16// Copyright(C) 2015 - 2021 by Bertini2 Development Team
17//
18// See <http://www.gnu.org/licenses/> for a copy of the license,
19// as well as COPYING. Bertini2 is provided with permitted
20// additional terms in the b2/licenses/ directory.
21
22// individual authors of this file include:
23// silviana amethyst, University of Wisconsin Eau Claire
24
30
31#ifndef BERTINI_EIGEN_EXTENSIONS_HPP
32#define BERTINI_EIGEN_EXTENSIONS_HPP
33
34
36
37#include <boost/serialization/complex.hpp>
38#include <boost/serialization/array.hpp>
39#include <boost/serialization/split_member.hpp>
40
41#define EIGEN_DENSEBASE_PLUGIN "bertini2/eigen_serialization_addon.hpp"
42
43#include <Eigen/Core>
44
45namespace {
46using mpfr_real = bertini::mpfr_float;
47using mpfr_complex = bertini::mpfr_complex;
48}
49
50namespace Eigen {
51
52 template<> struct NumTraits<mpfr_real> : GenericNumTraits<mpfr_real> // permits to get the epsilon, dummy_precision, lowest, highest functions
53 {
54
55 typedef mpfr_real Real;
56 typedef mpfr_real NonInteger;
57 typedef mpfr_real Nested;
58 enum {
59 IsComplex = 0,
60 IsInteger = 0,
61 IsSigned = 1,
62 RequireInitialization = 1, // yes, require initialization, otherwise get crashes
63 ReadCost = 20,
64 AddCost = 30,
65 MulCost = 40
66 };
67
68
69 inline static Real highest() {
70
71 return (mpfr_real(1) - epsilon()) * pow(mpfr_real(2),mpfr_get_emax()-1);//);//DefaultPrecision());
72 }
73
74 inline static Real lowest() {
75 return -highest();
76 }
77
78 inline static Real dummy_precision()
79 {
80 using bertini::DefaultPrecision;
81 return pow( mpfr_real(10),-int(DefaultPrecision()-3));
82 }
83
84 inline static Real epsilon()
85 {
86 using bertini::DefaultPrecision;
87 return pow(mpfr_real(10),-int(DefaultPrecision()));
88 }
89
90 static inline int digits10()
91 {
92 return bertini::DefaultPrecision();
93 // return internal::default_digits10_impl<T>::run();
94 }
95 //http://www.manpagez.com/info/mpfr/mpfr-2.3.2/mpfr_31.php
96 };
97
98
99 template<typename Expr1,typename Expr2, typename Expr3>
100 struct NumTraits<
101 boost::multiprecision::detail::expression<Expr1,
102 Expr2, Expr3, void, void>
103 > : NumTraits<mpfr_real> // permits to get the epsilon, dummy_precision, lowest, highest functions
104 {
105
106 typedef mpfr_real Real;
107 typedef mpfr_real NonInteger;
108 typedef mpfr_real Nested;
109
110 //http://www.manpagez.com/info/mpfr/mpfr-2.3.2/mpfr_31.php
111 };
112
113
114
120 template<> struct NumTraits<mpfr_complex> : NumTraits<mpfr_real>
121 {
122 typedef mpfr_real Real;
123 typedef mpfr_real NonInteger;
124 typedef mpfr_complex Nested;// Nested;
125 enum {
126 IsComplex = 1,
127 IsInteger = 0,
128 IsSigned = 1,
129 RequireInitialization = 1, // yes, require initialization, otherwise get crashes
130 ReadCost = 2 * NumTraits<Real>::ReadCost,
131 AddCost = 2 * NumTraits<Real>::AddCost,
132 MulCost = 4 * NumTraits<Real>::MulCost + 2 * NumTraits<Real>::AddCost
133 };
134
135 };
136
137 namespace internal {
138 template<>
139 struct abs2_impl<mpfr_complex>
140 {
141 static inline mpfr_real run(const mpfr_complex& x)
142 {
143 return real(x)*real(x) + imag(x)*imag(x);
144 }
145 };
146
147
148 template<> inline mpfr_complex random<mpfr_complex>()
149 {
151 }
152
153 template<> inline mpfr_complex random<mpfr_complex>(const mpfr_complex& a, const mpfr_complex& b)
154 {
155 return a + (b-a) * random<mpfr_complex>();
156 }
157
158 template<>
159 struct conj_helper<mpfr_complex, mpfr_complex, false, true>
160 {
161 typedef mpfr_complex Scalar;
162 EIGEN_STRONG_INLINE Scalar pmadd(const Scalar& x, const Scalar& y, const Scalar& c) const
163 { return c + pmul(x,y); }
164
165 EIGEN_STRONG_INLINE Scalar pmul(const Scalar& x, const Scalar& y) const
166 { return Scalar(real(x)*real(y) + imag(x)*imag(y), imag(x)*real(y) - real(x)*imag(y)); }
167 };
168
169 template<>
170 struct conj_helper<mpfr_complex, mpfr_complex, true, false>
171 {
172 typedef mpfr_complex Scalar;
173 EIGEN_STRONG_INLINE Scalar pmadd(const Scalar& x, const Scalar& y, const Scalar& c) const
174 { return c + pmul(x,y); }
175
176 EIGEN_STRONG_INLINE Scalar pmul(const Scalar& x, const Scalar& y) const
177 { return Scalar(real(x)*real(y) + imag(x)*imag(y), real(x)*imag(y) - imag(x)*real(y)); }
178 };
179
180 // see https://forum.kde.org/viewtopic.php?f=74&t=111176
181
182 //int
183 template<>
184 struct scalar_product_traits<int,mpfr_complex>
185 {
186 enum { Defined = 1 };
187 typedef mpfr_complex ReturnType;
188 };
189
190 template<>
191 struct scalar_product_traits<mpfr_complex, int>
192 {
193 enum { Defined = 1 };
194 typedef mpfr_complex ReturnType;
195 };
196
197 //long
198 template<>
199 struct scalar_product_traits<long,mpfr_complex>
200 {
201 enum { Defined = 1 };
202 typedef mpfr_complex ReturnType;
203 };
204
205 template<>
206 struct scalar_product_traits<mpfr_complex, long>
207 {
208 enum { Defined = 1 };
209 typedef mpfr_complex ReturnType;
210 };
211
212 //long long
213 template<>
214 struct scalar_product_traits<long long,mpfr_complex>
215 {
216 enum { Defined = 1 };
217 typedef mpfr_complex ReturnType;
218 };
219
220 template<>
221 struct scalar_product_traits<mpfr_complex, long long>
222 {
223 enum { Defined = 1 };
224 typedef mpfr_complex ReturnType;
225 };
226
227
228 //mpfr_real
229 template<>
230 struct scalar_product_traits<mpfr_real,mpfr_complex>
231 {
232 enum { Defined = 1 };
233 typedef mpfr_complex ReturnType;
234 };
235
236 template<>
237 struct scalar_product_traits<mpfr_complex, mpfr_real>
238 {
239 enum { Defined = 1 };
240 typedef mpfr_complex ReturnType;
241 };
242
243 //mpz_int
244 template<>
245 struct scalar_product_traits<bertini::mpz_int,mpfr_complex>
246 {
247 enum { Defined = 1 };
248 typedef mpfr_complex ReturnType;
249 };
250
251 template<>
252 struct scalar_product_traits<mpfr_complex, bertini::mpz_int>
253 {
254 enum { Defined = 1 };
255 typedef mpfr_complex ReturnType;
256 };
257
258 } // re: namespace internal
259} // re: namespace Eigen
260
261
262#include <Eigen/Core>
263#include <Eigen/Geometry>
264#include <Eigen/Eigenvalues>
265#include <Eigen/SVD>
266#include <Eigen/Dense>
267
268namespace bertini {
269
270 template<typename NumType> using Vec = Eigen::Matrix<NumType, Eigen::Dynamic, 1>;
271 template<typename NumType> using Mat = Eigen::Matrix<NumType, Eigen::Dynamic, Eigen::Dynamic>;
272
273
277 template<typename Derived>
278 inline
279 bool IsEmpty(Eigen::MatrixBase<Derived> const & v)
280 {
281 return (v.rows()==0) || (v.cols()==0);
282 }
283
284
290 template<typename Derived>
291 inline
292 unsigned Precision(Eigen::MatrixBase<Derived> const & v)
293 {
294 if (IsEmpty(v))
295 throw std::runtime_error("getting precision of empty object");
296
297 return Precision(v(0,0));
298 }
299
300
307 template<typename Derived>
308 unsigned PrecisionRequireUniform(Eigen::MatrixBase<Derived> const & v)
309 {
310 const auto a = Precision(v(0,0));
311 for (int ii=0; ii<v.cols(); ++ii)
312 for (int jj=0; jj<v.rows(); ++jj)
313 {
314 if (a!=Precision(v(jj,ii)))
315 {
316 std::stringstream ss;
317 ss << "non-uniform precision in object! (" << a << "!=" << Precision(v(jj,ii)) << ") at position " << jj << "," << ii;
318 throw std::runtime_error(ss.str());
319 }
320 }
321 return a;
322 }
323
324
331 template<typename Derived>
332 void Precision(Eigen::MatrixBase<Derived> & v, unsigned prec)
333 {
334 using bertini::Precision;
335 for (int ii=0; ii<v.cols(); ++ii)
336 for (int jj=0; jj<v.rows(); ++jj)
337 Precision(v(jj,ii),prec);
338 }
339
340
341
353 template<typename T>
354 inline
355 bool IsSmallValue(T const& testme)
356 {
357 using std::abs;
358 return abs(testme) <= Eigen::NumTraits<T>::epsilon()*100;
359 }
360
367 template<typename T>
368 inline
369 bool IsSymmRelDiffSmall(T const& a, T const& b, typename Eigen::NumTraits<T>::Real const& e)
370 {
371 using std::abs;
372 if (a==b)
373 return true;
374
375 typename Eigen::NumTraits<T>::Real c = abs(a-b);
376 return (c/abs(a) <= e) || (c/abs(b) <= e) ;
377 }
378
391 template<typename T>
392 inline
393 bool IsLargeChange(T const& numerator, T const& denomenator)
394 {
395 static_assert(!Eigen::NumTraits<T>::IsInteger, "IsLargeChange cannot be used safely on non-integral types");
396 using std::abs;
397 return abs(numerator/denomenator) >= 1/Eigen::NumTraits<T>::dummy_precision();
398 }
399
400 enum class MatrixSuccessCode
401 {
402 Success,
403 LargeChange,
404 SmallValue
405 };
406
416 template <typename Derived>
417 MatrixSuccessCode LUPartialPivotDecompositionSuccessful(Eigen::MatrixBase<Derived> const& LU)
418 {
419 #ifndef BERTINI_DISABLE_ASSERTS
420 assert(LU.rows()==LU.cols() && "non-square matrix in LUPartialPivotDecompositionSuccessful");
421 assert(LU.rows()>0 && "empty matrix in LUPartialPivotDecompositionSuccessful");
422 #endif
423
424 // this loop won't test entry (0,0). it's tested separately after.
425 for (unsigned int ii = LU.rows()-1; ii > 0; ii--)
426 {
427 if (IsSmallValue(LU(ii,ii)))
428 {
429 return MatrixSuccessCode::SmallValue;
430 }
431
432 if (IsLargeChange(LU(ii-1,ii-1),LU(ii,ii)))
433 {
434 return MatrixSuccessCode::LargeChange;
435 }
436 }
437
438 // this line is the reason for the above assert on non-empty matrix.
439 if (IsSmallValue(LU(0,0)))
440 {
441 return MatrixSuccessCode::SmallValue;
442 }
443
444 return MatrixSuccessCode::Success;
445 }
446
450 template <typename NumberType>
451 Eigen::Matrix<NumberType, Eigen::Dynamic, Eigen::Dynamic> KahanMatrix(unsigned int mat_size, NumberType c)
452 {
453 using std::sqrt;
454 NumberType s, scale(1.0);
455 s = sqrt( (NumberType(1.0)-c) * (NumberType(1.0)+c) );
456
457
458 Eigen::Matrix<NumberType, Eigen::Dynamic, Eigen::Dynamic> A(mat_size,mat_size);
459
460
461 for (unsigned int ii=0; ii<mat_size; ii++) {
462 for (unsigned int jj=0; jj<ii; jj++) {
463 A(ii,jj) = NumberType(0.0);
464 }
465 for (unsigned int jj=ii; jj<mat_size; jj++) {
466 A(ii,jj) = -c * NumberType(1.0);
467 }
468 }
469
470
471 for (unsigned int ii=0; ii<mat_size; ii++) {
472 A(ii,ii) += NumberType(1)+c;
473 }
474
475 for (unsigned int jj=0; jj<mat_size; jj++){
476 for (unsigned int kk=0;kk<mat_size;kk++){
477 A(jj,kk) *= scale;
478 }
479 scale *= s;
480 }
481
482 for (unsigned int jj=0;jj<mat_size;jj++){
483 for (unsigned int kk=0;kk<mat_size;kk++){
484 A(kk,jj)/= NumberType(jj) + NumberType(1);
485 }
486 }
487 return A;
488 }
489
490
500 template <typename NumberType>
501 inline
502 Mat<NumberType> RandomOfUnits(uint rows, uint cols)
503 {
504 return Mat<NumberType>(rows,cols).unaryExpr([](NumberType const& x) { return RandomUnit<NumberType>(); });
505 }
506
515 template <typename NumberType>
516 inline
517 Vec<NumberType> RandomOfUnits(uint size)
518 {
519 return Vec<NumberType>(size).unaryExpr([](NumberType const& x) { return RandomUnit<NumberType>(); });
520 }
521
522}
523
524
525// // the following code comes from
526// // https://stackoverflow.com/questions/18382457/eigen-and-boostserialize
527// // and adds support for serialization of Eigen types
528// //
529// // question asked by user Gabriel and answered by Shmuel Levine
530// // answer code repeated here verbatim.
531// // please update this comment if this code is changed,
532// // and post the modifications to the above referenced post on SO.
533// namespace boost{
534// namespace serialization{
535
536// template< class Archive,
537// class S,
538// int Rows_,
539// int Cols_,
540// int Ops_,
541// int MaxRows_,
542// int MaxCols_>
543// inline void save(
544// Archive & ar,
545// const Eigen::Matrix<S, Rows_, Cols_, Ops_, MaxRows_, MaxCols_> & g,
546// const unsigned int version)
547// {
548// int rows = g.rows();
549// int cols = g.cols();
550
551// ar & rows;
552// ar & cols;
553// ar & boost::serialization::make_array(g.data(), rows * cols);
554// }
555
556// template< class Archive,
557// class S,
558// int Rows_,
559// int Cols_,
560// int Ops_,
561// int MaxRows_,
562// int MaxCols_>
563// inline void load(
564// Archive & ar,
565// Eigen::Matrix<S, Rows_, Cols_, Ops_, MaxRows_, MaxCols_> & g,
566// const unsigned int version)
567// {
568// int rows, cols;
569// ar & rows;
570// ar & cols;
571// g.resize(rows, cols);
572// ar & boost::serialization::make_array(g.data(), rows * cols);
573// }
574
575// template< class Archive,
576// class S,
577// int Rows_,
578// int Cols_,
579// int Ops_,
580// int MaxRows_,
581// int MaxCols_>
582// inline void serialize(
583// Archive & ar,
584// Eigen::Matrix<S, Rows_, Cols_, Ops_, MaxRows_, MaxCols_> & g,
585// const unsigned int version)
586// {
587// split_free(ar, g, version);
588// }
589
590
591// } // namespace serialization
592// } // namespace boost
593
594
595
596
597#endif
dbl pow(const dbl &z, int power)
Definition double_extensions.hpp:88
bool IsLargeChange(T const &numerator, T const &denomenator)
Definition eigen_extensions.hpp:393
bool IsSymmRelDiffSmall(T const &a, T const &b, typename Eigen::NumTraits< T >::Real const &e)
Check whether two values are very close to each other.
Definition eigen_extensions.hpp:369
Mat< NumberType > RandomOfUnits(uint rows, uint cols)
Make a random matrix of units (numbers with norm 1).
Definition eigen_extensions.hpp:502
MatrixSuccessCode LUPartialPivotDecompositionSuccessful(Eigen::MatrixBase< Derived > const &LU)
Check the diagonal elements of an LU decomposition for small values and large ratios.
Definition eigen_extensions.hpp:417
unsigned PrecisionRequireUniform(Eigen::MatrixBase< Derived > const &v)
Query the precision of an Eigen object, requiring it to be non-empty, and of uniform precision.
Definition eigen_extensions.hpp:308
bool IsSmallValue(T const &testme)
Definition eigen_extensions.hpp:355
bool IsEmpty(Eigen::MatrixBase< Derived > const &v)
Checks whether the number of rows and columns are either 0.
Definition eigen_extensions.hpp:279
unsigned Precision(Eigen::MatrixBase< Derived > const &v)
Get the precision of an Eigen object. If the object is empty, it's the precision of a default-constru...
Definition eigen_extensions.hpp:292
Eigen::Matrix< NumberType, Eigen::Dynamic, Eigen::Dynamic > KahanMatrix(unsigned int mat_size, NumberType c)
Make a Kahan matrix with a given number type.
Definition eigen_extensions.hpp:451
Provides an Eigen-like NumTraits struct for querying traits of a number type.
complex rand()
Definition random.hpp:206