G+Smo  25.01.0
Geometry + Simulation Modules
 
Loading...
Searching...
No Matches
gsSturmSolver.h
1
2
3#include <gsPolynomial/gsMonomialPoly.h>
4
5
6namespace gismo{
7
8template<class T>
9class gsSturmSolver
10{
11
12
13};
14
18 template<typename T>
19 gsMatrix<T> FindRootIntervals(gsMonomialPoly<T> & poly, T eps)
20 {
21 gsMatrix<T> root(1, 3);
22 root.setZero();
23
24 root = CalcIntervals(poly, eps, root);
25 root.conservativeResize(root.rows() - 1, 3);
26 root = SortRoots(root);
27
28 return root;
29 }
30
31
34 template<typename T>
35 gsMatrix<T> CalcIntervals(const gsMonomialPoly<T> & poly, T eps, gsMatrix<T> rootIntervals)
36 {
37 gsMonomialPoly<T> copyPoly = poly;
38 gsVector<T> coeff = copyPoly.coefs();
39 int degree = copyPoly.basis().size() - 1;
40
41 // checks if the input polynomial has 0 as a root
42 int divByX = 0;
43
44 while (!copyPoly.isNull() && copyPoly.coefs()(0) == 0)
45 {
46 rootIntervals(rootIntervals.rows() - 1, 0) = 0;
47 rootIntervals(rootIntervals.rows() - 1, 1) = 0;
48 rootIntervals(rootIntervals.rows() - 1, 2) += 1;
49
50 gsMonomialBasis<T> monomialBasis(1);
51 gsMatrix<T> coefs(2, 1);
52 coefs << 0, 1;
53 gsMonomialPoly<T> x(monomialBasis, coefs);
54 copyPoly = PolyDivision(copyPoly, x, 1);
55 divByX = 1;
56 }
57
58 if (divByX == 1)
59 {
60 rootIntervals.conservativeResize(rootIntervals.rows() + 1, 3);
61 }
62
63 //if the polynomial is not constant, the sturm sequence is calculated
64 if (! copyPoly.isConstant() )
65 {
66 gsMatrix<T> sturmSeq(degree + 1, degree + 1);
67 sturmSeq = SturmSequence(copyPoly);
68
69 //checks if the polynomial has multiple roots
70 if (sturmSeq.bottomRows(1).isZero())
71 {
72 gsVector< T >vec = sturmSeq.row(sturmSeq.rows() - 2);
73 gsMonomialPoly<T >poly(copyPoly.basis(), vec);
74 rootIntervals = CalcIntervals(poly, eps, rootIntervals);
75 rootIntervals = CalcIntervals(PolyDivision(copyPoly, poly, 1), eps, rootIntervals);
76 }
77 // the polynomial doesn't have multiple roots
78 else{
79 RootIsolation(T(-CauchyBound(copyPoly)), CauchyBound(copyPoly),
80 eps, sturmSeq, rootIntervals);
81
82 }
83 }
84 return rootIntervals;
85 }
86
87
89 template <typename T>
90 void RootIsolation(T leftBound, T rightBound, T eps, gsMatrix<T> & sturmSeq, gsMatrix<T> & rootIntervals){
91
92 int roots = SignChanges(HornerEval(sturmSeq, leftBound)) - SignChanges(HornerEval(sturmSeq, rightBound));
93
94 //no roots in this interval
95 if (roots == 0) { return; }
96
97 //one root and the length of the intervals is <= 0.01
98 else if (roots == 1 && rightBound - leftBound <= 0.01)
99 {
100 rootIntervals(rootIntervals.rows() - 1, 0) = leftBound;
101 rootIntervals(rootIntervals.rows() - 1, 1) = rightBound;
102 rootIntervals(rootIntervals.rows() - 1, 2) = 1;
103 rootIntervals.conservativeResize(rootIntervals.rows() + 1, 3);
104 }
105 //more roots and the length of the interval is smaller than the border eps
106 else if (roots > 1 && rightBound - leftBound < eps)
107 {
108 rootIntervals(rootIntervals.rows() - 1, 0) = leftBound;
109 rootIntervals(rootIntervals.rows() - 1, 1) = rightBound;
110 rootIntervals(rootIntervals.rows() - 1, 2) = roots;
111 rootIntervals.conservativeResize(rootIntervals.rows() + 1, 3);
112 }
113
114 //more roots and the length of the interval is greater than eps
115 else
116 {
117 T bound = (rightBound + leftBound) / 2;
118 gsVector<T> f = sturmSeq.row(0);
119 T root_check = HornerEvalPoly(f, bound);
120
121 // the middle of the interval is a root
122 if (root_check == 0)
123 {
124 roots = SignChanges(HornerEval(sturmSeq, T(bound - eps/2)))
125 - SignChanges(HornerEval(sturmSeq, T(bound + eps/2)));
126 if (roots > 1)
127 {
128 rootIntervals(rootIntervals.rows() - 1, 0) = bound - eps / 2;
129 rootIntervals(rootIntervals.rows() - 1, 1) = bound + eps / 2;
130 rootIntervals(rootIntervals.rows() - 1, 2) = roots;
131 rootIntervals.conservativeResize(rootIntervals.rows() + 1, 3);
132 }
133 else
134 {
135 rootIntervals(rootIntervals.rows() - 1, 0) = bound;
136 rootIntervals(rootIntervals.rows() - 1, 1) = bound;
137 rootIntervals(rootIntervals.rows() - 1, 2) = 1;
138 rootIntervals.conservativeResize(rootIntervals.rows() + 1, 3);
139 }
140 RootIsolation(leftBound, T(bound - eps/2), eps, sturmSeq, rootIntervals);
141 RootIsolation(T(bound + eps/2), rightBound, eps, sturmSeq, rootIntervals);
142 }
143 // the middle of the interval is not a root, so a bisection is done
144 else
145 {
146 RootIsolation(leftBound, bound, eps, sturmSeq, rootIntervals);
147 RootIsolation(bound, rightBound, eps, sturmSeq, rootIntervals);
148
149 }
150 }
151 }
152
153
155 template<typename T>
156 T CauchyBound(gsMonomialPoly<T> &poly)
157 {
158 gsVector<T> vec = poly.coefs();
159
160 int lead = vec.size() - 1; // right-most non-zero
161 for (int i = vec.size() - 1; i >= 0; i--)
162 {
163 if (vec(i) != 0)
164 {
165 lead = i;
166 break;
167 }
168 }
169 return 1 + (vec/vec[lead]).array().abs().maxCoeff();
170 }
171
173 template<typename T>
174 gsMatrix<T> SturmSequence(gsMonomialPoly<T> & poly)
175 {
176 int deg = poly.basis().size() - 1;
177 gsMatrix<T> sturm(deg + 1, deg + 1);
178 sturm.setZero();
179
180 //first row = f
181 sturm.row(0) = poly.coefs().transpose();
182
183 //second row = f'
184 sturm.row(1) = PolyDerivWithSameDegree(poly).coefs().transpose();
185
186 if ( PolyDerivWithSameDegree(poly).isConstant() )
187 {
188 sturm.conservativeResize(2, sturm.cols());
189 return sturm;
190 }
191
192 // i-th row = -rem(f_(i-2), f_(i-1))
193 // until it is constant
194 gsVector<T> dividend;
195 gsVector<T> divisor;
196
197 for (int i = 2; i <= deg; i++)
198 {
199 dividend = sturm.row(i - 2);
200 divisor = sturm.row(i - 1);
201 gsMonomialPoly<T> poly1(poly.basis(), dividend);
202 gsMonomialPoly<T> poly2(poly.basis(), divisor);
203 gsMonomialPoly<T> poly3 = PolyDivision(poly1, poly2, 2);
204
205 if ( poly3.isNull() )
206 {
207 sturm.conservativeResize(i + 1, sturm.cols());
208 return sturm;
209 }
210
211
212 for (int j = 0; j < poly3.coefs().size(); j++)
213 {
214 sturm(i, j) -= poly3.coefs()(j);
215 }
216
217 if ( poly3.isConstant() )
218 {
219 sturm.conservativeResize(i + 1, sturm.cols());
220 return sturm;
221 }
222
223 }
224
225 return sturm;
226 }
227
230 template<typename T>
231 gsMonomialPoly<T> PolyDerivWithSameDegree(const gsMonomialPoly<T> & poly)
232 {
233 gsVector<T> deriv(poly.deg()+1);
234 //AM:
235 //deriv.topRows(poly.deg()) = gsVector<int>::LinSpaced(poly.deg(),1,poly.deg()).array()
236 // * poly.coefs().bottomRows(poly.deg()).array();
237
238 for (int i = 0; i < deriv.size() - 1; i++)
239 {
240 deriv(i) = poly.coefs()(i + 1)*(i + 1);
241 }
242 deriv(deriv.size() - 1) = 0;
243 return gsMonomialPoly<T>(poly.basis(), deriv);
244 }
245
246
251 template<typename T>
252 gsMonomialPoly<T> PolyDivision(const gsMonomialPoly<T> & dividendPoly,
253 const gsMonomialPoly<T> & divisorPoly, int num)
254 {
255 if (num != 1 && num != 2)
256 {
257 std::cout << "ERROR: The number is not in the corresponding range. The dividend will be returned" << std::endl;
258 return dividendPoly;
259 }
260 gsMonomialPoly<T> dividendCopy = dividendPoly;
261 gsMonomialPoly<T> divisorCopy = divisorPoly;
262
263 // storing the coefs of dividend and divisor seperately in a gsVector/gsMatrix
264 gsMatrix<T> dividend = dividendCopy.coefs().transpose();
265
266 gsVector<T> divisor(dividend.size());
267 divisor.setZero();
268 for (int i = 0; i < divisorCopy.coefs().size(); i++)
269 {
270 divisor(i) = divisorCopy.coefs()(i);
271 }
272
273
274 // getting the real degrees of dividend and divisor
275 int deg_dividend = dividend.size() - 1;
276
277 while (dividend(deg_dividend) == 0)
278 {
279 deg_dividend--;
280 }
281
282
283 int deg_divisor = divisor.size() - 1;
284
285 while (divisor(deg_divisor) == 0)
286 {
287 deg_divisor--;
288 }
289
290 if (deg_divisor > deg_dividend)
291 {
292 std::cout << "Error, the division is not possible. The degree of the divisor is greater than the degree of the dividend. The dividend will be returned";
293 return dividendPoly;
294 }
295
296
297 // Algorithm for polynomial long division
298 gsVector<T> quot(dividend.size());
299 gsVector<T> rem(dividend.size());
300
301 quot.setZero();
302 rem = dividend.transpose();
303 int deg_rem = deg_dividend;
304
305 int lead = 0;
306 T lead_coeff = 0;
307
308 gsVector<T> dummy;
309 while (!(rem.maxCoeff() == 0 && rem.minCoeff() == 0) && deg_rem >= deg_divisor)
310 {
311 lead = deg_rem - deg_divisor;
312 lead_coeff = rem(deg_rem) / divisor(deg_divisor);
313 quot(lead) = quot(lead) + lead_coeff;
314 dummy = ShiftRight(divisor, lead);
315 rem = rem - dummy * lead_coeff;
316 deg_rem = deg_dividend;
317
318 while (rem(deg_rem) == 0 && deg_rem > 0)
319 {
320 deg_rem--;
321 }
322 }
323
324 // returning the right output
325 if (num == 1){
326
327 gsMonomialBasis<T> monomial_basis(deg_dividend - deg_divisor);
328 gsMonomialPoly<T> polyQuot(monomial_basis, quot.head(deg_dividend - deg_divisor + 1));
329
330 return polyQuot;
331 }
332 else{
333
334 gsMonomialBasis<T> monomial_basis(deg_rem);
335 gsMonomialPoly<T> polyRem(monomial_basis, rem.head(deg_rem + 1));
336
337 return polyRem;
338 }
339
340
341 }
342
345 template <typename T>
346 gsVector<T> ShiftRight(const gsVector<T> & vec, int num)
347 {
348 gsVector<T> shift_vec(vec.size());
349 shift_vec.topRows(num).setZero();
350 const index_t b = vec.size()-num;
351 shift_vec.bottomRows(b) = vec.topRows(b);
352 return shift_vec;
353 }
354
355
356 //returns the number of sign changes of a vector
357 template <typename T>
358 int SignChanges(const gsVector<T> & vec)
359 {
360 // AM:
361 //int result = 0;
362 //for (int i = 1; i < vec.size(); ++i)
363 // if (vec[i-1]*vec[i] .. 0) ++result;
364
365 gsVector<T> vec_copy = vec;
366 for (int i = 0; i < vec.size(); i++)
367 {
368 vec_copy(i) = vec(i) / math::abs(vec(i));// 0, +1 or -1
369 }
370
371 int result = 0;
372 for (int i = 0; i < vec_copy.size() - 1; i++)
373 {
374 if (math::abs(vec_copy(i) + vec_copy(i + 1)) < 2) { result++; }
375
376 }
377 return result;
378 }
379
380
383 template <typename T>
385 {
386 int col = mat.cols();
387 gsVector<T> eval(mat.rows());
388 eval = mat.col(col - 1);
389
390 for (int i = 2; i <= mat.cols(); i++)
391 {
392 eval = eval*num + mat.col(col - i);
393
394 }
395 return eval;
396 }
397
398
400 template <typename T>
401 T HornerEvalPoly(const gsVector<T> & vec, T num)
402 {
403 T eval = vec(vec.size() - 1);
404
405 for (int i = 2; i <= vec.size(); i++)
406 {
407 eval = eval*num + vec(vec.size() - i);
408 }
409 return eval;
410 }
411
412
415 template<typename T>
417 {
418 gsMatrix<T> sort(unsort.rows(), 3);
419 sort.setZero();
420 T min = -1;
421 int position = -1;
422
423 for (int i = 0; i < unsort.rows(); i++)
424 {
425
426 min = unsort.col(0).minCoeff();
427 for (int j = 0; j < unsort.rows(); j++)
428 {
429 if (min == unsort(j, 0)){
430 position = j;
431 break;
432 }
433 }
434
435 sort.row(i) = unsort.row(position);
436 unsort(position, 0) = INT_MAX;
437 }
438
439 for (int i = 0; i < sort.rows()-1; i++)
440 {
441
442 if ((sort(i, 0) == sort(i + 1, 0) && sort(i, 1) <= sort(i + 1, 1)) ||
443 (sort(i, 0) <= sort(i + 1, 0) && sort(i, 1) == sort(i + 1, 1)))
444 {
445 sort(i, 2) += 1;
446 for (int j = i+1; j < sort.rows()-1; j++){
447 sort.row(j) = sort.row(j + 1);
448 }
449
450 sort.conservativeResize(sort.rows()- 1, 3);
451 --i;
452 }
453 }
454 return sort;
455 }
456
457}
458
459
460
461
A matrix with arbitrary coefficient type and fixed or dynamic size.
Definition gsMatrix.h:41
An univariate monomial polynomial basis. If the degree is p the basis is given by: [ 1,...
Definition gsMonomialBasis.h:24
A vector with arbitrary coefficient type and fixed or dynamic size.
Definition gsVector.h:37
#define index_t
Definition gsConfig.h:32
The G+Smo namespace, containing all definitions for the library.
gsMonomialPoly< T > PolyDerivWithSameDegree(const gsMonomialPoly< T > &poly)
Definition gsSturmSolver.h:231
T CauchyBound(gsMonomialPoly< T > &poly)
returns the Cauchy Bound of a Polynomial, which is 1+max(abs(a_i/a_n))
Definition gsSturmSolver.h:156
gsVector< T > HornerEval(gsMatrix< T > &mat, T num)
Definition gsSturmSolver.h:384
gsMonomialPoly< T > PolyDivision(const gsMonomialPoly< T > &dividendPoly, const gsMonomialPoly< T > &divisorPoly, int num)
Definition gsSturmSolver.h:252
gsVector< T > ShiftRight(const gsVector< T > &vec, int num)
Definition gsSturmSolver.h:346
gsMatrix< T > SturmSequence(gsMonomialPoly< T > &poly)
returns the sturm sequence in a gsMatrix
Definition gsSturmSolver.h:174
T HornerEvalPoly(const gsVector< T > &vec, T num)
evaluates a gsVector (which represents the coefficients of a polynomial) at value num
Definition gsSturmSolver.h:401
gsMatrix< T > SortRoots(gsMatrix< T > &unsort)
Definition gsSturmSolver.h:416
gsMatrix< T > CalcIntervals(const gsMonomialPoly< T > &poly, T eps, gsMatrix< T > rootIntervals)
Definition gsSturmSolver.h:35
void RootIsolation(T leftBound, T rightBound, T eps, gsMatrix< T > &sturmSeq, gsMatrix< T > &rootIntervals)
Algorithm for the isolation of the roots.
Definition gsSturmSolver.h:90
gsMatrix< T > FindRootIntervals(gsMonomialPoly< T > &poly, T eps)
Definition gsSturmSolver.h:19