5 #include "gsMonomialBasis.h"
6 #include "gsMonomialPoly.h"
11 template<
typename C>
class gsBairstowSolver
14 unsigned int max_iter;
18 std::vector< std::vector< std::complex<C> > > roots;
27 gsBairstowSolver() : eps(0.001), b0(0), c0(0), max_iter(50), aux(0), auxLen(0), status(-1), init_mode(0), polish_roots(true) { }
31 if (aux)
delete[] aux;
41 void solve(
const gsMonomialPoly<C> & poly){
50 if (Q[0].rows() > auxLen){
52 if (aux)
delete[] aux;
58 if (roots.size() != (
unsigned int)n) roots.resize(n);
71 for (component = 0; component < n; ++component){
72 if ((status = solveComponent()) < 0)
return;
82 int init_mode_orig(init_mode);
83 C b0_orig(b0), c0_orig(c0);
88 for (component = 0; component < n; ++component){
89 if ((status = polishRoots()) < 0)
break;
93 init_mode = init_mode_orig;
102 std::vector< std::complex<C> > getRoots(
unsigned int i){
104 "Root-vector which is out of range requested.");
111 const std::vector< std::complex<C> > getRoots(
unsigned int i)
const{
113 "Root-vector which is out of range requested.");
118 std::vector< std::vector< std::complex<C> > > getRoots(){
123 const std::vector< std::vector< std::complex<C> > > getRoots()
const{
128 unsigned int getMaxIterations()
const {
return max_iter; }
133 void setMaxIterations(
unsigned int value) { max_iter = value; }
136 C getEps()
const {
return eps; }
141 void setEps(
const C & value) { eps = value; }
146 "Initial coefficient which is out of range requested.");
161 void setInitial(
const C & coef0,
const C & coef1){
167 int getInitMode(){
return init_mode; }
172 void setInitMode(
int value){ init_mode = value; }
175 int getPolish(){
return polish_roots; }
180 void setPolish(
bool value){ polish_roots = value; }
185 int stat()
const {
return status; }
193 int solveComponent(){
196 int deg = this->degree(Q[0]);
198 if (deg < 0)
return -1;
200 roots[component] = std::vector< std::complex<C> >();
204 roots[component].reserve(deg);
211 for (; deg > 2; deg -= 2){
212 res = findQuFactor(i, deg);
213 if (res < 0)
return res;
220 roots[component].push_back(std::complex<C>(-Q[i](0, component) / Q[i](1, component)));
223 quadraticSolve(Q[i](1, component) / Q[i](2, component), Q[i](0, component) / Q[i](2, component));
236 int findQuFactor(
int i,
int d){
237 std::complex<C> s1, s2;
240 int out = findQuFactor(i, d, s1, s2);
242 roots[component].push_back(s1);
243 roots[component].push_back(s2);
253 int findQuFactor(
int i,
int d, std::complex<C> & sol1, std::complex<C> & sol2){
254 C b, c, b2, c2, r, s, rb, sb, rc, sc, dv, db, dc, eps2(eps * eps);
261 b = Q[i](d - 1, component) / Q[i](d, component);
262 c = Q[i](d - 2, component) / Q[i](d, component);
274 for (
unsigned int k = 0; k < max_iter; ++k){
276 div(Q[i], d, b, c, Q[1 - i]);
280 if (r*r <= eps2 && s*s <= eps2){
287 div(Q[1 - i], d - 2, b, c);
296 dv = sb * rc - sc * rb;
297 if (dv == 0)
return -1;
299 db = (r * sc - s * rc) / dv;
300 dc = (-r * sb + s * rb) / dv;
306 if ((db*db <= eps2*(b2 = b*b) || b2 <= eps2) && (dc*dc <= eps2*(c2 = c*c) || c2 <= eps2)){
314 if (out > 0) quadraticSolve(b, c, sol1, sol2);
324 if (roots[component].size() > 2){
325 int deg = roots[component].size(), out;
326 for (
typename std::vector< std::complex<C> >::iterator it = roots[component].begin() + 2;
327 it != roots[component].end() && it + 1 != roots[component].end();
331 b0 = -(it->real() + (it + 1)->real());
332 c0 = it->real() * (it + 1)->real() - it->imag() * (it + 1)->imag();
336 out = findQuFactor(0, deg, *it, *(it + 1));
337 if (out < 0)
return out;
351 for (
short_t d = coefs.rows() - 1; d >= 0; --d){
352 if (coefs(d, component) != 0)
return d;
361 void quadraticSolve(
const C & b,
const C & c){
362 std::complex<C> s1, s2;
365 quadraticSolve(b, c, s1, s2);
366 roots[component].push_back(s1);
367 roots[component].push_back(s2);
374 void quadraticSolve(
const C & b,
const C & c, std::complex<C> & s1, std::complex<C> & s2){
376 C discriminant(b * b - C(4) * c);
378 if (discriminant >= 0)
380 discriminant = sqrt(discriminant);
381 s1 = std::complex<C>((-b - discriminant) / TWO);
382 s2 = std::complex<C>((-b + discriminant) / TWO);
384 discriminant = sqrt(-discriminant) / TWO;
385 s1 = std::complex<C>(-b / TWO, -discriminant);
386 s2 = std::complex<C>(-b / TWO, discriminant);
397 GISMO_ASSERT( p.rows() > dp && auxLen > dp && quo.rows() > dp - 2,
398 "Invalid division-with-remainder in gsBairstow.");
403 for (k = 0; k <= dp; ++k) aux[k] = p(k, component);
404 for (k = dp - 2; k >= 0; --k){
405 quo(k, component) = aux[k + 2];
406 aux[k + 1] -= quo(k, component) * b;
407 aux[k] -= quo(k, component) * c;
416 void div(
const gsMatrix<C> & p,
int dp,
const C & b,
const C & c){
418 "Invalid division-with-remainder in gsBairstow.");
423 for (k = 0; k <= dp; ++k) aux[k] = p(k, component);
424 for (k = dp - 2; k >= 0; --k){
425 aux[k + 1] -= aux[k + 2] * b;
426 aux[k] -= aux[k + 2] * c;
Main header to be included by clients using the G+Smo library.
#define short_t
Definition: gsConfig.h:35
#define GISMO_ASSERT(cond, message)
Definition: gsDebug.h:89