sbasis-roots.cpp revision ccb552a7e79ca66f285ad9ccf933f956cc45dc06
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenk/** root finding for sbasis functions.
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenk * Copyright 2006 N Hurst
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenk * Copyright 2007 JF Barraud
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenk * It is more efficient to find roots of f(t) = c_0, c_1, ... all at once, rather than iterating.
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenk * multi-roots using bernstein method, one approach would be:
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenk take median and find roots of that
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenk whenever a segment lies entirely on one side of the median,
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenk find the median of the half and recurse.
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenk in essence we are implementing quicksort on a continuous function
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenk * the gsl poly roots finder is faster than bernstein too, but we don't use it for 3 reasons:
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenk a) it requires convertion to poly, which is numerically unstable
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenk b) it requires gsl (which is currently not a dependency, and would bring in a whole slew of unrelated stuff)
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenk c) it finds all roots, even complex ones. We don't want to accidently treat a nearly real root as a real root
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenkFrom memory gsl poly roots was about 10 times faster than bernstein in the case where all the roots
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenkare in [0,1] for polys of order 5. I spent some time working out whether eigenvalue root finding
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenkcould be done directly in sbasis space, but the maths was too hard for me. -- njh
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenkjfbarraud: eigenvalue root finding could be done directly in sbasis space ?
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenknjh: I don't know, I think it should. You would make a matrix whose characteristic polynomial was
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenkcorrect, but do it by putting the sbasis terms in the right spots in the matrix. normal eigenvalue
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenkroot finding makes a matrix that is a diagonal + a row along the top. This matrix has the property
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenkthat its characteristic poly is just the poly whose coefficients are along the top row.
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenkNow an sbasis function is a linear combination of the poly coeffs. So it seems to me that you
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenkshould be able to put the sbasis coeffs directly into a matrix in the right spots so that the
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenkcharacteristic poly is the sbasis. You'll still have problems b) and c).
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenkWe might be able to lift an eigenvalue solver and include that directly into 2geom. Eigenvalues
233b7c8a350fc6de2eea18a37ece8b7f32ba7e57tweenkalso allow you to find intersections of multiple curves but require solving n*m x n*m matrices.
using namespace std;
namespace Geom{
#ifdef USE_SBASIS_OF
return result;
return result;
#ifdef USE_SBASIS_OF
double a=sb[j][0];
v = res[0];
return res;
#ifdef USE_SBASIS_OF
double a=sb[j][0];
return res;
unfortunately, extra care is needed about rounding errors, and also to avoid the repetition of roots,
#ifdef USE_SBASIS_OF
double htol,
double vtol,
double fa,
double fb){
if (f.size()==0){
int idx;
// if (f.size()==1){
// if (idx_max==levels.size()) idx_max-=1;
if ((b-a)<htol){
unfortunately, extra care is needed about rounding errors, and also to avoid the repetition of roots,
double htol,
double vtol,
return(roots);
return( lower_bound( levels.begin(), levels.end(), Interval(x,x), compareIntervalMax) - levels.begin() );
return result;
unfortunately, extra care is needed about rounding errors, and also to avoid the repetition of roots,
double fa,
double fb,
if (f.size()==0){
unsigned idx;
if ( idxa == 0 ){
ta_lo = b;
ta_hi = b;
if ( idxb == 0 ){
tb_lo = a;
tb_hi = a;
double ft=f(t);
double a, double b, double tol){
return solsets;
std::vector<Interval> level_set (SBasis const &f, double level, double vtol, double a, double b, double tol){
std::vector<Interval> level_set (SBasis const &f, Interval const &level, double a, double b, double tol){
std::vector<std::vector<Interval> > level_sets (SBasis const &f, std::vector<double> const &levels, double vtol, double a, double b, double tol){
return res;
return res;
/** Find all t s.t s(t) = 0
switch(s.size()) {
return roots1(s);
switch(s.size()) {