Bertini 2 - C++ Core
Software for Numerical Algebraic Geometry
Loading...
Searching...
No Matches
patch.hpp
Go to the documentation of this file.
1//This file is part of Bertini 2.
2//
3//include/bertini2/system/patch.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//include/bertini2/system/patch.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 include/bertini2/system/patch.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_PATCH_HPP
32#define BERTINI_PATCH_HPP
33
35
39
40#include <vector>
41
42#include <Eigen/Dense>
43
44#include <boost/archive/text_oarchive.hpp>
45#include <boost/archive/text_iarchive.hpp>
46
47#include <boost/serialization/vector.hpp>
48
49namespace bertini {
50
51
52
53
85 class Patch
86 {
87
88 public:
89
95 Patch() : precision_(DefaultPrecision())
96 {}
97
98
102 Patch(Patch const& other)
103 {
104 variable_group_sizes_ = other.variable_group_sizes_;
105 precision_ = DefaultPrecision();
106
107 // a little shorthand unpacking the tuple
108 std::vector<Vec<mpfr_complex> >& coefficients_mpfr = std::get<std::vector<Vec<mpfr_complex> > >(this->coefficients_working_);
109 std::vector<Vec<dbl> >& coefficients_dbl = std::get<std::vector<Vec<dbl> > >(this->coefficients_working_);
110
111 coefficients_highest_precision_.resize(other.NumVariableGroups());
112 coefficients_mpfr.resize(variable_group_sizes_.size());
113 coefficients_dbl.resize(variable_group_sizes_.size());
114
115 for (unsigned ii(0); ii<other.NumVariableGroups(); ++ii)
116 {
117 auto curr_size = variable_group_sizes_[ii];
118
119 coefficients_highest_precision_[ii].resize(curr_size);
120 coefficients_dbl[ii].resize(curr_size);
121 coefficients_mpfr[ii].resize(curr_size);
122
123 for (unsigned jj(0); jj<curr_size; jj++)
124 {
125 coefficients_highest_precision_[ii](jj).precision(other.coefficients_highest_precision_[ii](jj).precision());
126
127 coefficients_highest_precision_[ii](jj) = other.coefficients_highest_precision_[ii](jj);
128
129 coefficients_dbl[ii](jj) = dbl(coefficients_highest_precision_[ii](jj));
130 coefficients_mpfr[ii](jj) = mpfr_complex(coefficients_highest_precision_[ii](jj));
131
132 assert(coefficients_highest_precision_[ii](jj) == other.coefficients_highest_precision_[ii](jj));
133 }
134 }
135 }
136
137
147 Patch(std::vector<unsigned> const& sizes) : variable_group_sizes_(sizes), coefficients_highest_precision_(sizes.size()), precision_(DefaultPrecision())
148 {
149 using bertini::Precision;
150 using bertini::multiprecision::RandomComplex;
151
152 std::vector<Vec<mpfr_complex> >& coefficients_mpfr = std::get<std::vector<Vec<mpfr_complex> > >(coefficients_working_);
153 std::vector<Vec<dbl> >& coefficients_dbl = std::get<std::vector<Vec<dbl> > >(coefficients_working_);
154
155 coefficients_highest_precision_.resize(sizes.size());
156 coefficients_dbl.resize(sizes.size());
157 coefficients_mpfr.resize(sizes.size());
158
159 for (size_t ii=0; ii<sizes.size(); ++ii)
160 {
161 // this produces coefficients at maximum precision.
162 coefficients_highest_precision_[ii].resize(sizes[ii]);
163 for (unsigned jj=0; jj<sizes[ii]; ++jj)
164 {
165 multiprecision::RandomComplexAssign(coefficients_highest_precision_[ii](jj), MaxPrecisionAllowed());
166 }
167
168 coefficients_dbl[ii].resize(sizes[ii]);
169 for (unsigned jj=0; jj<sizes[ii]; ++jj)
170 {
171 coefficients_dbl[ii](jj) = dbl(coefficients_highest_precision_[ii](jj));
172 }
173
174 // assignment preserves precision of source.
175 // https://github.com/boostorg/multiprecision/issues/75
176 coefficients_mpfr[ii].resize(sizes[ii]);
177 for (unsigned jj=0; jj<sizes[ii]; ++jj)
178 {
179 coefficients_mpfr[ii](jj) = coefficients_highest_precision_[ii](jj);
180 coefficients_mpfr[ii](jj).precision(precision_);
181 }
182
183 assert(Precision(coefficients_mpfr[ii](0))==precision_);
184 }
185 }
186
187
191 static Patch Random(std::vector<unsigned> const& sizes)
192 {
193 return Patch(sizes);
194 }
195
196
200 static Patch RandomReal(std::vector<unsigned> const& sizes)
201 {
203 using bertini::Precision;
204
205 Patch p;
206
207 p.variable_group_sizes_ = sizes;
208
209
210
211 std::vector<Vec<mpfr_complex> >& coefficients_mpfr = std::get<std::vector<Vec<mpfr_complex> > >(p.coefficients_working_);
212 std::vector<Vec<dbl> >& coefficients_dbl = std::get<std::vector<Vec<dbl> > >(p.coefficients_working_);
213
214 p.coefficients_highest_precision_.resize(sizes.size());
215 coefficients_mpfr.resize(sizes.size());
216 coefficients_dbl.resize(sizes.size());
217
218 for (size_t ii=0; ii<sizes.size(); ++ii)
219 {
220 p.coefficients_highest_precision_[ii].resize(sizes[ii]);
221 for (unsigned jj=0; jj<sizes[ii]; ++jj)
222 multiprecision::RandomRealAssign(p.coefficients_highest_precision_[ii](jj), MaxPrecisionAllowed());
223
224 coefficients_mpfr[ii] = p.coefficients_highest_precision_[ii];
225 Precision(coefficients_mpfr[ii],DefaultPrecision());
226 assert(Precision(coefficients_mpfr[ii](0))==DefaultPrecision());
227
228 coefficients_dbl[ii].resize(sizes[ii]);
229 for (unsigned jj=0; jj<sizes[ii]; ++jj)
230 coefficients_dbl[ii](jj) = dbl(p.coefficients_highest_precision_[ii](jj));
231 }
232
233 return p;
234 }
235
236
242 unsigned Precision() const
243 {
244 return precision_;
245 }
246
254 void Precision(unsigned new_precision) const
255 {
256 if (precision_==new_precision)
257 return;
258
259 using bertini::Precision;
260 std::vector<Vec<mpfr_complex> >& coefficients_mpfr = std::get<std::vector<Vec<mpfr_complex> > >(coefficients_working_);
261
262 for (unsigned ii = 0; ii < NumVariableGroups(); ++ii)
263 {
264 for (unsigned jj=0; jj<variable_group_sizes_[ii]; ++jj)
265 {
266 if (new_precision>precision_)
267 {
268 coefficients_mpfr[ii](jj) = coefficients_highest_precision_[ii](jj);
269 coefficients_mpfr[ii](jj).precision(new_precision);
270 }
271 else
272 coefficients_mpfr[ii](jj).precision(new_precision);
273
274 assert(Precision(coefficients_mpfr[ii](jj))==new_precision);
275 }
276 }
277
278 precision_ = new_precision;
279 }
280
281
282
283
284
285
296 template<typename Derived, typename T>
297 void EvalInPlace(Eigen::MatrixBase<Derived> & function_values, Vec<T> const& x) const
298 {
299 static_assert(std::is_same<typename Derived::Scalar,T>::value,"scalar types must match");
300
301 #ifndef BERTINI_DISABLE_ASSERTS
302 if (! (function_values.size()>=NumVariableGroups()) )
303 {
304 std::stringstream ss;
305 ss << "container for function values must be of length at least as long as the number of variable groups. the input vector into which to write is of length " << function_values.size();
306 throw std::runtime_error(ss.str());
307 }
308// assert((bertini::Precision(x(0))==DoublePrecision() || bertini::Precision(x(0)) == Precision())
309// && "precision of input vector must match current working precision of patch during evaluation"
310// );
311 #endif
312
313 // unpack from the tuple of working coefficients
314 const std::vector<Vec<T> >& coefficients = std::get<std::vector<Vec<T> > >(coefficients_working_);
315
316 unsigned offset(function_values.size() - NumVariableGroups()); // by precondition this number is at least 0. the precondition is ensured by the public wrapper
317 unsigned counter(0);
318 for (unsigned ii = 0; ii < NumVariableGroups(); ++ii)
319 {
320 T& value = function_values(ii+offset);
321 value = T(-1);
322 for (unsigned jj=0; jj<variable_group_sizes_[ii]; ++jj)
323 {
324 value += x(counter)*coefficients[ii](jj);
325 counter++;
326 }
327 }
328 }
329
336 template<typename T>
337 Vec<T> Eval(Vec<T> const& x) const
338 {
339 Vec<T> function_values = Vec<T>::Zero(NumVariableGroups());
340 EvalInPlace(function_values, x);
341 return function_values;
342 }
343
354 template<typename Derived, typename T>
355 void JacobianInPlace(Eigen::MatrixBase<Derived> & jacobian, Vec<T> const& x) const
356 {
357 static_assert(std::is_same<typename Derived::Scalar,T>::value,"scalar types must match");
358
359
360 #ifndef BERTINI_DISABLE_ASSERTS
361 assert(jacobian.rows()>=NumVariableGroups() && "input jacobian must have at least as many rows as variable groups");
362 assert(jacobian.cols()==NumVariables() && "input jacobian must have as many columns as the patch has variables");
363 assert(
364 (bertini::Precision(x(0))==DoublePrecision() || bertini::Precision(x(0)) == Precision())
365 && "precision of input vector must match current working precision of patch during evaluation"
366 );
367 #endif
368
369 const std::vector<Vec<T> >& coefficients = std::get<std::vector<Vec<T> > >(coefficients_working_);
370
371 unsigned offset(jacobian.rows() - NumVariableGroups()); // by precondition this number is at least 0. the precondition is ensured by the public wrapper
372 unsigned counter(0);
373 for (unsigned ii = 0; ii < NumVariableGroups(); ++ii)
374 for (unsigned jj=0; jj<variable_group_sizes_[ii]; ++jj)
375 jacobian(ii+offset,counter++) = coefficients[ii](jj);
376 }
377
384 template<typename T>
385 Mat<T> Jacobian(Vec<T> const& x) const
386 {
387 Mat<T> jacobian = Mat<T>::Zero(NumVariableGroups(), NumVariables());
388 JacobianInPlace(jacobian, x);
389 return jacobian;
390 }
391
392
403 template<typename T>
404 void RescalePointToFitInPlace(Vec<T> & x) const
405 {
406 #ifndef BERTINI_DISABLE_ASSERTS
407 assert(x.size() == NumVariables() && "input point for rescaling to fit a patch must have same length as total number of variables being patched, in all variable groups.");
408 assert((bertini::Precision(x(0))==DoublePrecision() || bertini::Precision(x(0)) == Precision())
409 && "precision of input vector must match current working precision of patch during rescaling"
410 );
411 #endif
412
413 const std::vector<Vec<T> >& coefficients = std::get<std::vector<Vec<T> > >(coefficients_working_);
414
415 unsigned starting_index_counter(0);
416 for (unsigned ii=0; ii<NumVariableGroups(); ii++)
417 {
418 auto subvec = x.segment(starting_index_counter,variable_group_sizes_[ii]);
419 subvec /= subvec.transpose() * coefficients[ii];
420 starting_index_counter += variable_group_sizes_[ii];
421 }
422 }
423
431 template <typename T>
432 Vec<T> RescalePoint(Vec<T> const& x) const
433 {
434 Vec<T> x_rescaled = x;
435 RescalePointToFitInPlace(x_rescaled);
436 return x_rescaled;
437 }
438
444 unsigned NumVariableGroups() const
445 {
446 return variable_group_sizes_.size();
447 }
448
449
453 unsigned NumVariables() const
454 {
455 unsigned num_vars(0);
456 for (auto v : variable_group_sizes_)
457 num_vars += v;
458 return num_vars;
459 }
460
461
462 friend std::ostream& operator<<(std::ostream & out, Patch const& p)
463 {
464 out << p.NumVariableGroups() << " variable groups being patched\n";
465 unsigned counter(0);
466 for (auto& c : p.coefficients_highest_precision_)
467 {
468 out << "patch " << counter++ << " has " << c.size() << " coefficients:\n";
469 out << c << "\n";
470 }
471 out << "current patch precision: " << p.Precision() << "\n";
472 return out;
473 }
474
480 bool operator==(Patch const& rhs) const
481 {
483 return false;
484 if (NumVariables()!=rhs.NumVariables())
485 return false;
486 for (unsigned ii=0; ii<NumVariableGroups(); ii++)
487 if (variable_group_sizes_[ii]!=rhs.variable_group_sizes_[ii])
488 return false;
489 for (unsigned ii=0; ii<NumVariableGroups(); ii++)
490 if (coefficients_highest_precision_[ii]!=rhs.coefficients_highest_precision_[ii])
491 return false;
492
493
494 return true;
495 }
496
500 bool operator!=(Patch const& rhs) const
501 {
502 return !(*this==rhs);
503 }
504
505 private:
506
508 //
509 // Data members
510 //
512
513 std::vector< Vec< mpfr_complex > > coefficients_highest_precision_;
514
515 mutable std::tuple< std::vector< Vec< mpfr_complex > >, std::vector< Vec< dbl > > > coefficients_working_;
516
517 std::vector<unsigned> variable_group_sizes_;
518
519 mutable unsigned precision_;
520
521 // add serialization support through boost.
522
523 friend class boost::serialization::access;
524
525 template <typename Archive>
526 void serialize(Archive& ar, const unsigned version) {
527 ar & precision_;
528
529 ar & coefficients_highest_precision_;
530
531 ar & std::get<0>(coefficients_working_);
532 ar & std::get<1>(coefficients_working_);
533 ar & variable_group_sizes_;
534
535 }
536
537 };
538
539
540}
541
542
543#endif // re: include guards
544
545
An affine chart on a product of projective spaces.
Definition patch.hpp:86
Vec< T > RescalePoint(Vec< T > const &x) const
Rescale a point so that it satisfies the patch equations herein contained.
Definition patch.hpp:432
void JacobianInPlace(Eigen::MatrixBase< Derived > &jacobian, Vec< T > const &x) const
Evaluate the Jacobian matrix, in place.
Definition patch.hpp:355
Vec< T > Eval(Vec< T > const &x) const
Evaluate the patch at a point.
Definition patch.hpp:337
void Precision(unsigned new_precision) const
Set the precision of the patch.
Definition patch.hpp:254
void RescalePointToFitInPlace(Vec< T > &x) const
Rescale a point so that it satisfies the patch equations herein contained.
Definition patch.hpp:404
static Patch RandomReal(std::vector< unsigned > const &sizes)
Construct random REAL patch on a space.
Definition patch.hpp:200
unsigned NumVariableGroups() const
Get the number of variable groups.
Definition patch.hpp:444
Patch()
Default constructor.
Definition patch.hpp:95
void EvalInPlace(Eigen::MatrixBase< Derived > &function_values, Vec< T > const &x) const
Evaluate the patch at a point, in place.
Definition patch.hpp:297
Patch(std::vector< unsigned > const &sizes)
Constructor making a random complex patch on a space whose structure is described by the input argume...
Definition patch.hpp:147
Mat< T > Jacobian(Vec< T > const &x) const
Evaluate the Jacobian matrix, in place.
Definition patch.hpp:385
static Patch Random(std::vector< unsigned > const &sizes)
Construct a random complex patch on a space.
Definition patch.hpp:191
unsigned Precision() const
Get the current precision of the patch.
Definition patch.hpp:242
unsigned NumVariables() const
Get the number of variables in the patch.
Definition patch.hpp:453
bool operator==(Patch const &rhs) const
Check whether two patches are the same.
Definition patch.hpp:480
Patch(Patch const &other)
Definition patch.hpp:102
bool operator!=(Patch const &rhs) const
Check whether two patches are different.
Definition patch.hpp:500
Bertini extensions of the Eigen linear algebra library.
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
The main multiprecision complex number type. This is essentially boost::multiprecision' complex.
Extensions to the Boost.Multiprecision library.
Provides an Eigen-like NumTraits struct for querying traits of a number type.
complex RandomReal()
Definition random.hpp:180
void RandomRealAssign(complex &a, unsigned num_digits)
Definition random.hpp:168