On Wed, Dec 20, 2023 at 07:40:00AM +0800, Qian Yun wrote:
> integrate(atan(x*(x^2+1)^(1/2)),x)
> integrate(tanh(x)/(exp(x)+exp(2*x))^(1/2),x)
> integrate((2+2*tan(x)+tan(x)^2)^(1/2),x)
> ...
> 
> These integrals are different between trunk and this patch.
> (same as 1.3.9.)

Newer patch, fixes bunch of problems with previous patches.
Previous patch did not handle correclty the following:

integrate((14*x^2-18*x-4)/(x^4+(-7)*x^2+6*x+1), x)
-- poly x^4 - 7*x^2 + 6*x + 1, 4 real roots

integrate((-8*x^2-24*x-4)/(x^4+4*x^2+8*x+1), x)
-- poly x^4  + 4*x^2  + 8*x + 1, 2 complex roots and 2 real roots

-- 
                              Waldek Hebisch

-- 
You received this message because you are subscribed to the Google Groups 
"FriCAS - computer algebra system" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/fricas-devel/ZYMxdnX7ym5Lb6Kj%40fricas.org.
diff --git a/src/algebra/rsimp.spad b/src/algebra/rsimp.spad
index 04322e8..22f00f5 100644
--- a/src/algebra/rsimp.spad
+++ b/src/algebra/rsimp.spad
@@ -10,8 +10,10 @@ RootUtilities(R, F) : Exports == Implementation where
   UP ==> SUP(F)
   Exports ==> with
     complex_roots : UP -> Union(r_rec, "failed")
-    quartic2 : UP -> List(C_rec)
+    quartic2 : (UP, F) -> Union(r_rec, "failed")
       ++ quartic2(p) should be local but conditional
+    my_sqrt : F -> F
+      ++ my_sqrt(a) should be local but conditional
     my_root3 : F -> F
       ++ my_root3(a) should be local but conditional
 
@@ -24,7 +26,7 @@ RootUtilities(R, F) : Exports == Implementation where
     P ==> SparseMultivariatePolynomial(R, K)
 
     dummy := create()$SingletonAsOrderedSet
- 
+
     root_pair(a : F, b : F) : C_rec == [a, b]
 
     root4(a : F) : F ==
@@ -54,58 +56,78 @@ RootUtilities(R, F) : Exports == Implementation where
             degree(fr1) ~= 1 => error "impossible"
             -coefficient(fr1, 0)/coefficient(fr1, 1)
 
-        -- Q = (-4)*u*v^2+(4*u^3+2*a*u+b)
-        quartic3(r1 : F, a0 : F, a : F, b : F) : List(C_rec) ==
+        do_rp(r : F, q : F, res1 : r__rec) : Union(r_rec, "failed") ==
+            (su := sign(q)) case "failed" => "failed"
+            (0 < su@Integer) =>
+                qr := my_sqrt(q)
+                [res1.reals, cons(root_pair(r, qr), res1.complexes)]
+            qr := my_sqrt(-q)
+            [cons(r + qr, cons(r - qr, res1.reals)), res1.complexes]
+
+        -- Square of real part u and square of imaginary part v
+        -- satisfy (-4)*u*v^2+(4*u^3+2*a*u+b) = 0
+        -- so given real part we compute imaginary parts.
+        -- In fact, above u is square of average of two roots and
+        -- -v^2 is square od half of difference between roots, so
+        -- this also works for real roots.
+        quartic3(r1 : F, a0 : F, a : F, b : F) : Union(r_rec, "failed") ==
             rr := my_sqrt(r1)
             qq := r1 + (1/2::F)*a
             q1 := qq + b*rr/(4*r1)
+            res1 := do_rp(rr + a0, q1, [[], []])
+            res1 case "failed" => "failed"
             q2 := qq - b*rr/(4*r1)
-            [root_pair(rr - a0/(4::F), my_sqrt(q1)),
-                root_pair(-rr - a0/(4::F), my_sqrt(q2))]
+            do_rp(-rr + a0, q2, res1)
 
-        do_f2(del : F, a2 : F, b2 : F, a0 : F, a : F, b : F) : List(C_rec) ==
+        do_f2(del : F, a2 : F, b2 : F, a0 : F, a : F, b : F
+             ) : Union(r_rec, "failed") ==
             d2 := my_sqrt(del)
-            (su := sign(d2)) case "failed" => []
+            (su := sign(d2)) case "failed" => "failed"
             if su@Integer < 0 then
                 d2 := -d2
             quartic3((-b2 + d2)/(2*a2), a0, a, b)
-            
-        quartic2(p : UP) : List(C_rec) ==
-            lc := leadingCoefficient(p)
-            p := (1/lc)*p
-            a0 := coefficient(p, 3)
-            p := eval(p, dummy, monomial(1, 1)$UP - (a0/4::F)::UP)
+
+        -- Squares of averages of pairs of roots of quartic satisfy
+        -- equation 64u^3 + 32au^2 + (-16c+4a^2)*u - b^2 = 0.
+        -- If the qubic factors, and we can determine needed
+        -- signs, then this works, otherwise fails.
+        quartic2(p : UP, a0 : F) : Union(r_rec, "failed") ==
             a := coefficient(p, 2)
             b := coefficient(p, 1)
             c := coefficient(p, 0)
             xx := monomial(1, 1)$UP
-            r := 64*xx^3 + 32*a*xx^2 
+            r := 64*xx^3 + 32*a*xx^2
             r := r + (-16*c+4*a^2)*xx
             r := r - (b^2)::UP
             fr := factor(r)
             fl := factorList(fr)
-            #fl = 1 => []
-            #fl = 3 =>
+            #fl = 1 => "failed"
+            flf : List(UP) := []
+            for fac in fl repeat
+                f1 := fac.factor
+                fac.exponent = 2 =>
+                    flf := cons(f1, cons(f1, flf))
+                flf := cons(f1, flf)
+            #flf = 3 =>
                 r1 : F
                 cnt : Integer := 0
-                for fac in fl repeat
-                    f1 := fac.factor
+                for f1 in flf repeat
                     cc := coefficient(f1, 0)/coefficient(f1, 1)
-                    (su := sign(cc)) case "failed" => return []
+                    (su := sign(cc)) case "failed" => return "failed"
                     if su@Integer < 0 then
-                        cnt > 0 => return []
-                        cnt := 1
+                        cnt := cnt + 1
+                        cnt > 1 => iterate
                         r1 := cc
                 cnt = 0 => error "impossible"
                 quartic3(-r1, a0, a, b)
-            #fl = 2 =>
+            #flf = 2 =>
                 r1 : F
-                f1 := first(fl).factor
-                f2 := second(fl).factor
-                if (degree(f2) = 1) then
+                f1 := first(flf)
+                f2 := second(flf)
+                if degree(f2) = 1 then
                     (f1, f2) := (f2, f1)
                 r1 := -coefficient(f1, 0)/coefficient(f1, 1)
-                (su := sign(r1)) case "failed" => return []
+                (su := sign(r1)) case "failed" => return "failed"
                 s1 := su@Integer
                 a2 := coefficient(f2, 2)
                 b2 := coefficient(f2, 1)
@@ -122,17 +144,22 @@ RootUtilities(R, F) : Exports == Implementation where
                             return do_f2(del, a2, b2, a0, a, b)
                         return quartic3(r1, a0, a, b)
                 su := sign(b2)
-                su case "failed" or not(0 < su@Integer) => return []
+                su case "failed" or not(0 < su@Integer) => return "failed"
                 su := sign(a2*coefficient(f2, 0))
                 if su case "failed" or not(0 < su@Integer) then
-                    return []
+                    return "failed"
                 quartic3(r1, a0, a, b)
             error "impossible"
 
     else
 
-        quartic2(p : UP) : List(C_rec) == []
- 
+        quartic2(p : UP, a0 : F) : Union(r_rec, "failed") == "failed"
+
+        my_sqrt(a : F) ==
+            rec := froot(a, 2)$PolynomialRoots(IndexedExponents(K), K, R, P, F)
+            rec.exponent = 2 => sqrt(a)
+            rec.coef*rec.radicand
+
         my_root3(a : F) : F ==
             rec := froot(a, 3)$PolynomialRoots(IndexedExponents(K), K, R, P, F)
             rec.exponent = 3 => a^(1/3)
@@ -156,22 +183,61 @@ RootUtilities(R, F) : Exports == Implementation where
             [[-r1 + a0], [root_pair(r1/(2::F) + a0, sqrt(3::F)*r1/(2::F))]]
         "failed"
 
+    quartic0(p : UP, a0 : F) : Union(r_rec, "failed") ==
+        pu := p exquo monomial(1, 1)$UP
+        pu case "failed" => error "impossible"
+        p := pu@UP
+        ru := qubic(p)
+        ru case "failed" => "failed"
+        r1 := ru@r_rec
+        rl : List(F) := [a0]
+        for r in r1.reals repeat
+            rl := cons(r + a0, rl)
+        cl : List(C_rec) :=
+            empty?(r1.complexes) => []
+            cp := first(r1.complexes)
+            [root_pair(cp.real + a0, cp.imag)]
+        [rl, cl]
+
     quartic(p : UP) : Union(r_rec, "failed") ==
+        coefficient(p, 0) = 0 => quartic0(p, 0)
+        lc := leadingCoefficient(p)
+        p := (1/lc)*p
+        a0 := -coefficient(p, 3)/(4::F)
+        p := eval(p, dummy, monomial(1, 1)$UP + a0::UP)
         ground?(rp := reductum(p)) =>
             a := ground(rp)
-            s := sign(a)
-            s case "failed" => "failed"
-            si := s@Integer
-            si = 1 =>
+            a = 0 => [[a0, a0, a0, a0], []]
+            (su := sign(a)) case "failed" => "failed"
+            (si := su@Integer) = 1 =>
                 r1 := root4(a/(4::F*leadingCoefficient(p)))
-                [[], [root_pair(r1, r1), root_pair(-r1, r1)]]
+                [[], [root_pair(r1 + a0, r1), root_pair(-r1 + a0, r1)]]
             si = -1 =>
                 r1 := rootSimp(zeroOf(p))
-                [[r1, -r1], [root_pair(0, r1)]]
+                [[r1 + a0, -r1 + a0], [root_pair(a0, r1)]]
             error "impossible"
-        res1 := quartic2(p)
-        not(empty?(res1)) => [[], res1]
-        "failed"
+        coefficient(p, 0) = 0 => quartic0(p, a0)
+        coefficient(p, 1) = 0 =>
+            b := coefficient(p, 2)
+            c := coefficient(p, 0)
+            del := b*b - 4*c
+            (su := sign(del)) case "failed" => "failed"
+            not((si := su@Integer) < 0) =>
+                r1 := my_sqrt(del)
+                x1 := (-b + r1)/(2::F)
+                x2 := (-b - r1)/(2::F)
+                (su := sign(x1)) case "failed" => "failed"
+                (su@Integer < 0) =>
+                    [[], [root_pair(a0, my_sqrt(-x1)),
+                          root_pair(a0, my_sqrt(-x2))]]
+                (su := sign(x2)) case "failed" => "failed"
+                r2 := my_sqrt(x1)
+                (su@Integer < 0) =>
+                    [[r2 + a0, -r2 + a0], [root_pair(a0, my_sqrt(-x2))]]
+                r3 := my_sqrt(x2)
+                [[r2 + a0, -r2 + a0, r3 + a0, -r3 + a0], []]
+            quartic2(p, a0)
+        quartic2(p, a0)
 
     complex_roots(p : UP) : Union(r_rec, "failed") ==
         d := degree(p)

Reply via email to