sagemath / sage

Main repository of SageMath
https://www.sagemath.org
Other
1.37k stars 462 forks source link

FriCAS rootOf translation does not return, part 2 #32143

Open mantepse opened 3 years ago

mantepse commented 3 years ago
sage: var("y, a")
sage: f = fricas.zerosOf (y^4 + y + a, y); f
            +-----------------------------+
            |       2                    2
           \|- 3 %y1  - 2 %y0 %y1 - 3 %y0   - %y1 - %y0
[%y0, %y1, --------------------------------------------,
                                 2
    +-----------------------------+
    |       2                    2
 - \|- 3 %y1  - 2 %y0 %y1 - 3 %y0   - %y1 - %y0
 ----------------------------------------------]
                        2

sage: f[1].sage()

does not return.

The reason is that there is the lack of a suitable equivalent for implicitly defined roots in the presence of extra variables.

Depends on #32133

Component: interfaces: optional

Keywords: FriCAS

Author: Martin Rubey

Issue created by migration from https://trac.sagemath.org/ticket/32143

mantepse commented 3 years ago

Changed keywords from none to FriCAS

mantepse commented 3 years ago
comment:2

Worse:

sage: f = fricas.zerosOf (y^5 + y + a, y);
sage: f[1].sage()
RuntimeError: no explicit roots found
mkoeppe commented 3 years ago
comment:3

So you are looking for a generalization of the function sage.functions.other.complex_root_of?

mantepse commented 3 years ago
comment:4

Replying to @mkoeppe:

So you are looking for a generalization of the function sage.functions.other.complex_root_of?

Yes, that's another way to put it.

I am not very familiar with the SymbolicRing, my root_of object does not really need to be able to do anything. Of course, it would be nice if one could compute with it (e.g., plugging it into the polynomial could give zero, and similar simplifications), but that is not necessary.

mkoeppe commented 3 years ago
comment:5

Yes, that's how complex_root_of behaves - it stays unevaluated until forced to be numerically evaluated. Currently it is only backed by a sympy function that only handles the case of polynomials with constant coefficients.

oscarbenjamin commented 1 year ago

I'm not sure exactly what fricas.zerosOf is doing. It looks like a parametric representation of the set of roots but I don't see why two parameters would be needed if there is only one symbol in the polynomial. It doesn't look as if the result depends on a.

I have thought many times about adding something like a symbolic generalisation of RootOf to SymPy but I'm not entirely sure how it should behave or even if it is definitely a good idea.

A SymPy RootOf represents a definite root of a polynomial with explicit rational coefficients using an irreducible polynomial in Q[x] and a real or complex bounding interval. This is just a generic way to represent any algebraic number. Root isolation is used to identify and then assign numbers to the bounding intervals so that the roots can be ordered unambiguously. This ordering makes it possible to identify the roots by index like RootOf(poly, 0), RootOf(poly, 1), ... so that each RootOf is a well-defined number. The SymPy functions minpoly and Poly.same_root can be used to reduce any expression representing an algebraic number to this form.

Extending this to the case of roots of polynomials with symbolic coefficients is difficult though because we are no longer talking about numbers but algebraic functions: https://en.wikipedia.org/wiki/Algebraic_function These are multivalued functions (representing the multiple roots) but there is no way to uniquely identify the different roots using bounding intervals or a numbering scheme as is used by RootOf. You could try to define it so that you have something like

a = AlgebraicFunction(x, x**5 + x + y, i)

where the index i identifies a root in the same way as RootOf. The idea would then be that substituting say y=1 would could reduce this to a RootOf with the same index:

a.subs(y, 1) -> RootOf(x**5 + x + 1, i)

The problem though is that the ordering scheme for RootOf would make a a discontinuous function of y. The set of roots actually depends continuously on any symbols like y though provided all coefficients are continuous and the leading coefficient is nonzero.

I don't see a way to unambiguously identify a "particular root" as a continuous function of y and so I wonder if it even makes sense to try and do so. One alternative is just to say that an AlgebraicFunction should be treated as a multivalued function so that it symbolically represents any and all of the roots at the same time. While it might be useful to have such an AlgebraicFunction it might also be tricky to work with. For example substituting numbers for all symbols would not reduce it to an unambiguous number because it really represents a finite set rather than an individual number. On the other hand other things like differentiation etc could work by using implicit differentiation and expressing the result in terms of AlgebraicFunction.

Then the question is if we only want to represent the set of roots of a polynomial does having an AlgebraicFunction object help any more than just having a RootSet object as a set rather than an expression? Maybe even just using the polynomial itself as an equation is better than trying to have a semi-explicit representation for its roots.

oldk1331 commented 10 months ago

It returns a very large radical expression in a few seconds, with sage-10.2 and FriCAS-1.3.9.

As said in https://github.com/sagemath/sage/issues/34420, the correct approach is to use implicit roots in the sage interface for FriCAS.

oldk1331 commented 10 months ago

Hi @oscarbenjamin ,

I'm not sure exactly what fricas.zerosOf is doing. It looks like a parametric representation of the set of roots but I don't see why two parameters would be needed if there is only one symbol in the polynomial. It doesn't look as if the result depends on a.

a is implicitly used in the definition of %y0:

(1) -> zerosOf (y^4 + y + a, y)

   (1)
               +-----------------------------+
               |       2                    2
              \|- 3 %y1  - 2 %y0 %y1 - 3 %y0   - %y1 - %y0
   [%y0, %y1, --------------------------------------------,
                                    2
       +-----------------------------+
       |       2                    2
    - \|- 3 %y1  - 2 %y0 %y1 - 3 %y0   - %y1 - %y0
    ----------------------------------------------]
                           2
                                              Type: List(Expression(Integer))
(2) -> definingPolynomial %y0

               4
   (2)  a + %y0  + %y0
                                                    Type: Expression(Integer)
(3) -> %y2

         +-----------------------------+
         |       2                    2
        \|- 3 %y1  - 2 %y0 %y1 - 3 %y0   - %y1 - %y0
   (3)  --------------------------------------------
                              2
                                                    Type: Expression(Integer)
(4) -> %y3

           +-----------------------------+
           |       2                    2
        - \|- 3 %y1  - 2 %y0 %y1 - 3 %y0   - %y1 - %y0
   (4)  ----------------------------------------------
                               2
                                                    Type: Expression(Integer)

Also as you can see from above, %y2 and %y3 are also implicitly defined.

Or you can see from another form:

(1) -> rootsOf(y^4 + y + a, y)

   (1)  [%y0, %y1, %y2, - %y2 - %y1 - %y0]
                                              Type: List(Expression(Integer))

As said in comment#5, complex_root_of can only handle numeric coefficients, and from https://groups.google.com/g/sage-devel/c/AOfOuZkQ4_Q , that sage can't represent rootSum, so the translation from FriCAS to sage is impossible right now.

BTW, other than explicitly asking for roofOf objects, most rootOf objects comes from integration: expansion of rootSum. The good news is that FriCAS is making improvements to return radicals instead of rootOf when possible, otherwise return rootSum instead of rootOf.