sandbox/huet/src/lagrangian_caps/smallest_root_cubic.h

    In this file, we implement a routine to find the smallest real root of a third-order polynomial, in absolute value.

    typedef struct realQuadraticRoots {
        bool real;
        double roots[2];
    } realQuadraticRoots;
    
    realQuadraticRoots real_quadratic_roots(double* p) {
        realQuadraticRoots result;
        double a, b, c;
        a = p[2]; b = p[1]; c = p[0];
        double epsilon = 1.e-16;
        if (fabs(a) < epsilon) {
            result.real = true;
            result.roots[0] = (fabs(b) > epsilon) ? -c/b : HUGE;
            result.roots[1] = HUGE;
            return result;
        }
    
        double delta = sq(b) - 4*a*c;
        if (fabs(delta) > epsilon && delta < 0) {
            result.real = false;
            result.roots[0] = HUGE;
            result.roots[1] = HUGE;
        }
        if (fabs(delta) > epsilon && delta > 0) {
            result.real = true;
            double r1, r2;
            r1 = (-b - sqrt(delta))/(2*a);
            r2 = (-b + sqrt(delta))/(2*a);
            result.roots[0] = fabs(r1) > fabs(r2) ? r2 : r1;
            result.roots[1] = fabs(r1) > fabs(r2) ? r1 : r2;
        }
        if (fabs(delta) < epsilon) {
            result.real = true;
            result.roots[0] = -b/(2*a);
            result.roots[1] = -b/(2*a);
        }
        return result;
    }
    
    trace
    double find_smallest_real_root(double* a) {
        double epsilon = 1.e-10;
            
        if (fabs(a[3]) > epsilon) {

    Solve 3rd-order polynomial:

            double alpha = a[2]/a[3];
            double beta = a[1]/a[3];
            double gamma = a[0]/a[3];
            double Q = (sq(alpha) - 3*beta)/9;
            double R = (2*cube(alpha) - 9*alpha*beta + 27*gamma)/54;
    
            if (sq(R) < cube(Q)) {
                double theta = acos(R/sqrt(cube(Q)));
                double r1 = -2*sqrt(Q)*cos(theta/3) - alpha/3;
                double r2 = -2*sqrt(Q)*cos((theta + 2*pi)/3) - alpha/3;
                double r3 = -2*sqrt(Q)*cos((theta - 2*pi)/3) - alpha/3;
                double min_root = (fabs(r1) < fabs(r2)) ? (fabs(r1) < fabs(r3) ?
                    r1 : r3) : (fabs(r2) < fabs(r3) ? r2 : r3);
                return min_root;
            }
            else {
                double A = -sign(R)*cbrt(fabs(R) + sqrt(sq(R) - cube(Q)));
                double B = (fabs(A) > epsilon) ? Q/A : 0;
                double root = (A + B) - alpha/3;
                return root;
            }
        }
    
        if (fabs(a[2]) > epsilon) {

    Solve 2nd-order polynomial

            realQuadraticRoots my_roots = real_quadratic_roots(a);
            if (my_roots.real == false) {
                fprintf(stderr, "Warning: no real roots found in find_smallest_real_root\n");
                return 0.;
            }
            double root1, root2;
            root1 = my_roots.roots[0];
            root2 = my_roots.roots[1];
            double smallest_real_root = (fabs(root1) > fabs(root2)) ? root2 : root1;
            return smallest_real_root;
        }
    
        if (fabs(a[1]) > epsilon) {

    Solve linear function

            return -a[0]/a[1];
        }
    
        fprintf(stderr, "Warning: giving constant function instead of third-order \
            polynomial in find_smallest_real_root.");
        return 0.;
    }