Opened 2 years ago

Closed 2 months ago

#28641 closed enhancement (invalid)

improve polynomial conversion from Fricas

Reported by: chapoton Owned by:
Priority: major Milestone: sage-duplicate/invalid/wontfix
Component: interfaces: optional Keywords: FriCAS
Cc: mantepse, charpent Merged in:
Authors: Frédéric Chapoton Reviewers:
Report Upstream: N/A Work issues:
Branch: Commit:
Dependencies: Stopgaps:

Status badges

Description (last modified by chapoton)

see https://ask.sagemath.org/question/48431/why-this-integral-fail-using-fricas-algorithm/

for the original bug report:

integrate(sqrt(2)*x^2 + 2*x,x, algorithm="fricas")

Change History (35)

comment:1 Changed 2 years ago by chapoton

  • Branch set to u/chapoton/28641
  • Commit set to dc1761eb48e0a28b93f4409020bb4d6d1435f937
  • Description modified (diff)
  • Status changed from new to needs_review

New commits:

dc1761esome improvements in Fricas interface

comment:2 follow-up: Changed 2 years ago by charpent

Hmmm...

sage: ft=fricas(t); ft
 +-+
\|2
sage: ft.parent()
FriCAS
sage: ft.sage()
1.414213562373095?
sage: ft.sage().parent()
Algebraic Field
sage: ft.sage()^2
2.000000000000000?
sage: t^2
2
sage: (ft.sage()^2).parent()
Algebraic Field
sage: (t^2).parent()
Symbolic Ring

We may loose the aymbolic representation of some quantities. And so, inconsistently:

sage: u=log(2); u
log(2)
sage: fu=fricas(u); fu
log(2)
sage: fu.sage()
log(2)
sage: fu.sage().parent()
Symbolic Ring

Ditto for exponentials. Potentially worse for trig:

sage: t
sqrt(2)
sage: arcsin(t/2)
1/4*pi
sage: arcsin(ft.sage()/2)
arcsin(0.7071067811865475?)

Anyway, ptestalllong underway for the current version (https://git.sagemath.org/sage.git/commit?id=dc1761eb48e0a28b93f4409020bb4d6d1435f937) of this patch.

comment:3 in reply to: ↑ 2 Changed 2 years ago by charpent

Replying to charpent:

[ Snip... ]

Even more inconsistent:

sage: fricas(sqrt(pi))
 +---+
\|%pi
sage: fricas(sqrt(pi)).sage()
sqrt(pi)

Couldn't we have fricas(sqrt(2)).sage()==sqrt(2) ?

comment:4 follow-ups: Changed 2 years ago by charpent

  • Status changed from needs_review to needs_work

Never mind :

charpent@zen-book-flip:/usr/local/sage-P3-2$ sage -t --long --warn-long 192.4 src/sage/interfaces/fricas.py 
Running doctests with ID 2019-10-20-19-15-43-ce51a938.
Git branch: t/28641/28641
Using --optional=build,dochtml,dot2tex,fricas,gap_packages,giacpy_sage,libsemigroups,memlimit,python2,sage
Doctesting 1 file.
sage -t --long --warn-long 192.4 src/sage/interfaces/fricas.py
**********************************************************************
File "src/sage/interfaces/fricas.py", line 1693, in sage.interfaces.fricas.FriCASElement._sage_
Failed example:
    fricas("x^2/2").sage()                                        # optional - fricas
Exception raised:
    Traceback (most recent call last):
      File "/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/doctest/forker.py", line 681, in _run
        self.compile_and_execute(example, compiler, test.globs)
      File "/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/doctest/forker.py", line 1123, in compile_and_execute
        exec(compiled, globs)
      File "<doctest sage.interfaces.fricas.FriCASElement._sage_[19]>", line 1, in <module>
        fricas("x^2/2").sage()                                        # optional - fricas
      File "/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/interface.py", line 1081, in sage
        return self._sage_(*args, **kwds)
      File "/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/fricas.py", line 1928, in _sage_
        for idx, cf in zip(monoms, coeffs)})
      File "sage/structure/parent.pyx", line 900, in sage.structure.parent.Parent.__call__ (build/cythonized/sage/structure/parent.c:9198)
        return mor._call_(x)
      File "sage/structure/coerce_maps.pyx", line 162, in sage.structure.coerce_maps.DefaultConvertMap_unique._call_ (build/cythonized/sage/structure/coerce_maps.c:4556)
        raise
      File "sage/structure/coerce_maps.pyx", line 157, in sage.structure.coerce_maps.DefaultConvertMap_unique._call_ (build/cythonized/sage/structure/coerce_maps.c:4448)
        return C._element_constructor(x)
      File "/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/rings/polynomial/polynomial_ring.py", line 476, in _element_constructor_
        return C(self, x, check, is_gen, construct=construct, **kwds)
      File "sage/rings/polynomial/polynomial_rational_flint.pyx", line 262, in sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint.__init__ (build/cythonized/sage/rings/polynomial/polynomial_rational_flint.cpp:5378)
        for deg, e in x.iteritems():
    TypeError: an integer is required
**********************************************************************
File "src/sage/interfaces/fricas.py", line 1753, in sage.interfaces.fricas.FriCASElement._sage_
Failed example:
    fricas("matrix [[x^n/2^m for n in 0..5] for m in 0..3]").sage()         # optional - fricas, long time
Exception raised:
    Traceback (most recent call last):
      File "/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/doctest/forker.py", line 681, in _run
        self.compile_and_execute(example, compiler, test.globs)
      File "/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/doctest/forker.py", line 1123, in compile_and_execute
        exec(compiled, globs)
      File "<doctest sage.interfaces.fricas.FriCASElement._sage_[37]>", line 1, in <module>
        fricas("matrix [[x^n/2^m for n in 0..5] for m in 0..3]").sage()         # optional - fricas, long time
      File "/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/interface.py", line 1081, in sage
        return self._sage_(*args, **kwds)
      File "/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/fricas.py", line 1846, in _sage_
        rows = self.listOfLists().sage()
      File "/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/interface.py", line 1081, in sage
        return self._sage_(*args, **kwds)
      File "/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/fricas.py", line 1838, in _sage_
        return [self.elt(k).sage() for k in range(1, n + 1)]
      File "/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/fricas.py", line 1838, in <listcomp>
        return [self.elt(k).sage() for k in range(1, n + 1)]
      File "/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/interface.py", line 1081, in sage
        return self._sage_(*args, **kwds)
      File "/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/fricas.py", line 1838, in _sage_
        return [self.elt(k).sage() for k in range(1, n + 1)]
      File "/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/fricas.py", line 1838, in <listcomp>
        return [self.elt(k).sage() for k in range(1, n + 1)]
      File "/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/interface.py", line 1081, in sage
        return self._sage_(*args, **kwds)
      File "/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/fricas.py", line 1928, in _sage_
        for idx, cf in zip(monoms, coeffs)})
      File "sage/structure/parent.pyx", line 900, in sage.structure.parent.Parent.__call__ (build/cythonized/sage/structure/parent.c:9198)
        return mor._call_(x)
      File "sage/structure/coerce_maps.pyx", line 162, in sage.structure.coerce_maps.DefaultConvertMap_unique._call_ (build/cythonized/sage/structure/coerce_maps.c:4556)
        raise
      File "sage/structure/coerce_maps.pyx", line 157, in sage.structure.coerce_maps.DefaultConvertMap_unique._call_ (build/cythonized/sage/structure/coerce_maps.c:4448)
        return C._element_constructor(x)
      File "/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/rings/polynomial/polynomial_ring.py", line 476, in _element_constructor_
        return C(self, x, check, is_gen, construct=construct, **kwds)
      File "sage/rings/polynomial/polynomial_rational_flint.pyx", line 262, in sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint.__init__ (build/cythonized/sage/rings/polynomial/polynomial_rational_flint.cpp:5378)
        for deg, e in x.iteritems():
    TypeError: an integer is required
**********************************************************************
1 item had failures:
   2 of  45 in sage.interfaces.fricas.FriCASElement._sage_
    [253 tests, 2 failures, 35.90 s]
----------------------------------------------------------------------
sage -t --long --warn-long 192.4 src/sage/interfaces/fricas.py  # 2 doctests failed
----------------------------------------------------------------------
Total time for all tests: 41.0 seconds
    cpu time: 4.0 seconds
    cumulative wall time: 35.9 seconds

==> needs_work

I'll peruse the other ptestalllong failures (usually transient) in order to find other (new) (permanent) problems.

comment:5 in reply to: ↑ 4 Changed 2 years ago by charpent

Replying to charpent:

[ Snip... ]

I'll peruse the other ptestalllong failures (usually transient) in order to find other (new) (permanent) problems.

FWIW, no new permanent failure beyond the one related to FriCAS, the transient failures are those already reported in sage-release.

comment:6 Changed 2 years ago by charpent

  • Cc charpent added

Adding myself to the Cc list.

comment:7 in reply to: ↑ 4 Changed 2 years ago by charpent

Replying to charpent:

[ Snip... ]

From your patch:

+                gens = R.variable_names()
+                coeffs = (base_ring(cf.sage()) for cf in self.coefficients())

The problem is here, IMSHO: I think that the base ring should be the base ring of the expression as a whole. This would avoid the intrusion of QQ or QQbar in symbolic expression having interger or fractional exponents, whose double translation (sage --> FriCAS --> sage) ends up in QQ.

+                monoms = (m.degree() for m in self.monomials())
+
+                def vers_exposant(idx):
+                    return tuple(idx[v] if v in idx else 0 for v in gens)
+
+                return R({vers_exposant(idx.sage()): cf
+                          for idx, cf in zip(monoms, coeffs)})

HTH,

comment:8 Changed 2 years ago by git

  • Commit changed from dc1761eb48e0a28b93f4409020bb4d6d1435f937 to 0bf95407d96a15022e458aea53cd861d830c3fb5

Branch pushed to git repo; I updated commit sha1. New commits:

0bf9540trac 28641 fix for fricas polynomials

comment:9 follow-ups: Changed 2 years ago by chapoton

In my opinion, getting results in something else than the horrible SR ring is a welcome improvement.

Something else: the back conversion of lists and matrices is extremely slow, and I have no idea how to fix that.

comment:10 in reply to: ↑ 9 ; follow-up: Changed 2 years ago by mantepse

Replying to chapoton:

In my opinion, getting results in something else than the horrible SR ring is a welcome improvement.

I agree. I didn't look at the details, so please just take it as a hint: you can (and should) tell FriCAS in which domain you want to compute. If you don't, FriCAS will "guess" a convenient domain for you, which most of the time works very well.

However, maybe it makes sense if, within sage, the conversion from sage to fricas preserves the domain. For example:

sage: fricas(sqrt(2)).domainOf()
AlgebraicNumber()

would be better

sage: fricas("sqrt(2)::EXPR INT").domainOf()
Expression(Integer())

Apparently, conversion from QQbar is not yet implemented, but this should not be hard.

Something else: the back conversion of lists and matrices is extremely slow, and I have no idea how to fix that.

Indeed, this is a big problem. The correct fix would be to write a proper interface, bypassing pexpect. This thread contains a sketch (!) of a proof of concept: https://groups.google.com/d/msg/fricas-devel/qYzrY-92Q2A/EnJ_82FZAQAJ

comment:11 in reply to: ↑ 9 Changed 2 years ago by charpent

Replying to chapoton:

In my opinion, getting results in something else than the horrible SR ring is a welcome improvement.

In this specific case, I disagree absolutely : SR allows to use a lot of knowlegde not accessible when these values are expressed as algrebraics (as already remarked, arcsin(sqrt(2)/2)) is recognized as pi/4, but not arcsin(0.707?), even if in this specific case, the expressed value can be recovered by .radical_expression()). Similarly, this change of representation may cause Sage to miss some simplifications or factorizations.

More generally, one should not unexpectedly change a representation to another with different possibilities.

Something else: the back conversion of lists and matrices is extremely slow, and I have no idea how to fix that.

This is anor=ther problem, that should be treated in another ticker.

comment:12 in reply to: ↑ 10 ; follow-up: Changed 2 years ago by charpent

Replying to mantepse:

Replying to chapoton:

In my opinion, getting results in something else than the horrible SR ring is a welcome improvement.

I agree.

I don't (see my reply to chapoton).

I didn't look at the details, so please just take it as a hint: you can (and should) tell FriCAS in which domain you want to compute. If you don't, FriCAS will "guess" a convenient domain for you, which most of the time works very well.

However, maybe it makes sense if, within sage, the conversion from sage to fricas preserves the domain. For example:

sage: fricas(sqrt(2)).domainOf()
AlgebraicNumber()

would be better

sage: fricas("sqrt(2)::EXPR INT").domainOf()
Expression(Integer())

No. Non. Nope. Nyet. (Or, as in the British Commons, no, no, no, no, no, no, no, no. And no).

You don't know if your "2" is the second non-null integer, (sin(2*x)/x).limit(x=0) or something else. The only "polyvalent" representation is SR(2).Which, I agree, is horribly inefficient, because it is polysemic.

Apparently, conversion from QQbar is not yet implemented, but this should not be hard.

I wouldn't wager my (supposedly) eternal soul on this one:

sage: QQbar(arcsin(1/2))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-9-b60e7a0af1e6> in <module>()
----> 1 QQbar(arcsin(Integer(1)/Integer(2)))

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/structure/parent.pyx in sage.structure.parent.Parent.__call__ (build/cythonized/sage/structure/parent.c:9198)()
    898         if mor is not None:
    899             if no_extra_args:
--> 900                 return mor._call_(x)
    901             else:
    902                 return mor._call_with_args(x, args, kwds)

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/structure/coerce_maps.pyx in sage.structure.coerce_maps.DefaultConvertMap_unique._call_ (build/cythonized/sage/structure/coerce_maps.c:4556)()
    160                 print(type(C), C)
    161                 print(type(C._element_constructor), C._element_constructor)
--> 162             raise
    163 
    164     cpdef Element _call_with_args(self, x, args=(), kwds={}):

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/structure/coerce_maps.pyx in sage.structure.coerce_maps.DefaultConvertMap_unique._call_ (build/cythonized/sage/structure/coerce_maps.c:4448)()
    155         cdef Parent C = self._codomain
    156         try:
--> 157             return C._element_constructor(x)
    158         except Exception:
    159             if print_warnings:

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/rings/qqbar.py in _element_constructor_(self, x)
   1176             return AlgebraicNumber(x._descr)
   1177         elif hasattr(x, '_algebraic_'):
-> 1178             return x._algebraic_(QQbar)
   1179         return AlgebraicNumber(x)
   1180 

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/symbolic/expression.pyx in sage.symbolic.expression.Expression._algebraic_ (build/cythonized/sage/symbolic/expression.cpp:11585)()
   1503         """
   1504         from sage.symbolic.expression_conversions import algebraic
-> 1505         return algebraic(self, field)
   1506 
   1507     def __hash__(self):

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/symbolic/expression_conversions.py in algebraic(ex, field)
   1178         0
   1179     """
-> 1180     return AlgebraicConverter(field)(ex)
   1181 
   1182 ##############

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/symbolic/expression_conversions.py in __call__(self, ex)
    216                 div = self.get_fake_div(ex)
    217                 return self.arithmetic(div, div.operator())
--> 218             return self.arithmetic(ex, operator)
    219         elif operator in relation_operators:
    220             return self.relation(ex, operator)

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/symbolic/expression_conversions.py in arithmetic(self, ex, operator)
   1028                 return exp(expt)._algebraic_(self.field)
   1029 
-> 1030         raise TypeError("unable to convert %r to %s"%(ex, self.field))
   1031 
   1032     def composition(self, ex, operator):

TypeError: unable to convert 1/6*pi to Algebraic Field

Something else: the back conversion of lists and matrices is extremely slow, and I have no idea how to fix that.

Indeed, this is a big problem. The correct fix would be to write a proper interface, bypassing pexpect. This thread contains a sketch (!) of a proof of concept: https://groups.google.com/d/msg/fricas-devel/qYzrY-92Q2A/EnJ_82FZAQAJ

I'd be very wary on this one. This has been done recently with R, and the result isn't (yet) beyond all criticism...

comment:13 in reply to: ↑ 12 ; follow-up: Changed 2 years ago by mantepse

Replying to charpent:

Replying to mantepse:

Replying to chapoton:

In my opinion, getting results in something else than the horrible SR ring is a welcome improvement.

I agree.

I don't (see my reply to chapoton).

I didn't look at the details, so please just take it as a hint: you can (and should) tell FriCAS in which domain you want to compute. If you don't, FriCAS will "guess" a convenient domain for you, which most of the time works very well.

However, maybe it makes sense if, within sage, the conversion from sage to fricas preserves the domain. For example:

sage: fricas(sqrt(2)).domainOf()
AlgebraicNumber()

would be better

sage: fricas("sqrt(2)::EXPR INT").domainOf()
Expression(Integer())

No. Non. Nope. Nyet. (Or, as in the British Commons, no, no, no, no, no, no, no, no. And no).

You seem to have a very strong opinion on that. In any case, this is how the interface currently (mostly) works, but if you want to do it differently, please go ahead.

You don't know if your "2" is the second non-null integer, (sin(2*x)/x).limit(x=0) or something else. The only "polyvalent" representation is SR(2).Which, I agree, is horribly inefficient, because it is polysemic.

I thought that, essentially, sagemath follows the idea that every object has a type. So, sage actually knows the type of "2" within an expression.

I would suggest to use this - and I think that the current interface does use this information quite a lot.

In FriCAS, every object *must* have a proper type. There is no way you can invert a square array of integers. (FriCAS is not very strict about itself, so you may find lots of counterexamples.)

Apparently, conversion from QQbar is not yet implemented, but this should not be hard.

I wouldn't wager my (supposedly) eternal soul on this one:

sage: QQbar(arcsin(1/2))

I don't understand - this is not an algebraic number. What do you want to show?

comment:14 follow-up: Changed 2 years ago by chapoton

  • Status changed from needs_work to needs_review

I think that this is ready for review.

Further fixes and enhacements could be done in later tickets. This ticket is fixing a precise problem, the integral in the description.

comment:15 in reply to: ↑ 14 Changed 2 years ago by charpent

  • Status changed from needs_review to needs_work

Replying to chapoton:

I think that this is ready for review.

Further fixes and enhacements could be done in later tickets. This ticket is fixing a precise problem, the integral in the description.

Nope:

sage: f=x*sqrt(2)
sage: bool(f.integrate(x, algorithm="fricas").diff(x)==f.integrate(x).diff(x))
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/interface.py in __init__(self, parent, value, is_name, name)
    707             try:
--> 708                 self._name = parent._create(value, name=name)
    709             except (TypeError, RuntimeError, ValueError) as x:

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/maxima_lib.py in _create(self, value, name)
    605             else:
--> 606                 self.set(name, value)
    607         except RuntimeError as error:

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/maxima_lib.py in set(self, var, value)
    514         cmd = '%s : %s$'%(var, value.rstrip(';'))
--> 515         self.eval(cmd)
    516 

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/maxima_lib.py in _eval_line(self, line, locals, reformat, **kwds)
    460                 if statement:
--> 461                     maxima_eval("#$%s$" % statement)
    462         if not reformat:

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/libs/ecl.pyx in sage.libs.ecl.EclObject.__call__ (build/cythonized/sage/libs/ecl.c:7779)()
    804         """
--> 805         lispargs = EclObject(list(args))
    806         return ecl_wrap(ecl_safe_apply(self.obj,(<EclObject>lispargs).obj))

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/libs/ecl.pyx in sage.libs.ecl.EclObject.__init__ (build/cythonized/sage/libs/ecl.c:7313)()
    669         if len(args) != 0:
--> 670             self.set_obj(python_to_ecl(args[0]))
    671 

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/libs/ecl.pyx in sage.libs.ecl.python_to_ecl (build/cythonized/sage/libs/ecl.c:6357)()
    484         else:
--> 485             L=cl_cons(python_to_ecl(pyobj[0]),Cnil)
    486             ptr=L

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/libs/ecl.pyx in sage.libs.ecl.python_to_ecl (build/cythonized/sage/libs/ecl.c:6051)()
    465         s=str_to_bytes(pyobj)
--> 466         return ecl_safe_read_string(s)
    467     elif isinstance(pyobj,bytes):

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/libs/ecl.pyx in sage.libs.ecl.ecl_safe_read_string (build/cythonized/sage/libs/ecl.c:5530)()
    385     o = ecl_cstring_to_base_string_or_nil(s)
--> 386     o = ecl_safe_funcall(read_from_string_clobj,o)
    387     return o

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/libs/ecl.pyx in sage.libs.ecl.ecl_safe_funcall (build/cythonized/sage/libs/ecl.c:5297)()
    364         s = si_coerce_to_base_string(ecl_values(1))
--> 365         raise RuntimeError("ECL says: {}".format(
    366             char_to_str(ecl_base_string_pointer_safe(s))))

RuntimeError: ECL says: THROW: The catch MACSYMA-QUIT is undefined.

During handling of the above exception, another exception occurred:

TypeError                                 Traceback (most recent call last)
<ipython-input-25-463b9051345c> in <module>()
----> 1 bool(f.integrate(x, algorithm="fricas").diff(x)==f.integrate(x).diff(x))

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/symbolic/expression.pyx in sage.symbolic.expression.Expression.__nonzero__ (build/cythonized/sage/symbolic/expression.cpp:19521)()
   2918             # lot of basic Sage objects can't be put into maxima.
   2919             from sage.symbolic.relation import test_relation_maxima
-> 2920             return test_relation_maxima(self)
   2921 
   2922         self_is_zero = self._gobj.is_zero()

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/symbolic/relation.py in test_relation_maxima(relation)
    490         [k is noninteger]
    491     """
--> 492     m = relation._maxima_()
    493 
    494     #Handle some basic cases first

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/symbolic/expression.pyx in sage.symbolic.expression.Expression._maxima_ (build/cythonized/sage/symbolic/expression.cpp:7806)()
    813             # Maybe not such a great idea because the "default" interface is another one
    814             from sage.calculus.calculus import maxima
--> 815             return super(Expression, self)._interface_(maxima)
    816         else:
    817             return super(Expression, self)._interface_(session)

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/structure/sage_object.pyx in sage.structure.sage_object.SageObject._interface_ (build/cythonized/sage/structure/sage_object.c:5532)()
    674             except Exception:
    675                 raise NotImplementedError("coercion of object %s to %s not implemented:\n%s\n%s" % (repr(self), I))
--> 676         X = I(s)
    677         if c:
    678             try:

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/interface.py in __call__(self, x, name)
    286 
    287         if isinstance(x, string_types):
--> 288             return cls(self, x, name=name)
    289         try:
    290             # Special methods do not and should not have an option to

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/interface.py in __init__(self, parent, value, is_name, name)
    708                 self._name = parent._create(value, name=name)
    709             except (TypeError, RuntimeError, ValueError) as x:
--> 710                 raise TypeError(x)
    711 
    712     def _latex_(self):

TypeError: ECL says: THROW: The catch MACSYMA-QUIT is undefined.

Missing this elementary test is no small beer...

===>needs_work

comment:16 in reply to: ↑ 13 ; follow-up: Changed 2 years ago by charpent

Replying to mantepse:

[ Snip... ]

I thought that, essentially, sagemath follows the idea that every object has a type. So, sage actually knows the type of "2" within an expression.

Indeed. But by converting SR(2) to QQbar(2), you lose information. Worse:

sage: ((pi/sqrt(2))*QQbar(sqrt(2))-pi).iz_zero()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-29-f8bf3b60b3d2> in <module>()
----> 1 ((pi/sqrt(Integer(2)))*QQbar(sqrt(Integer(2)))-pi).iz_zero()

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/structure/element.pyx in sage.structure.element.Element.__getattr__ (build/cythonized/sage/structure/element.c:4608)()
    487             AttributeError: 'LeftZeroSemigroup_with_category.element_class' object has no attribute 'blah_blah'
    488         """
--> 489         return self.getattr_from_category(name)
    490 
    491     cdef getattr_from_category(self, name):

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/structure/element.pyx in sage.structure.element.Element.getattr_from_category (build/cythonized/sage/structure/element.c:4717)()
    500         else:
    501             cls = P._abstract_element_class
--> 502         return getattr_from_other_class(self, cls, name)
    503 
    504     def __dir__(self):

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/cpython/getattr.pyx in sage.cpython.getattr.getattr_from_other_class (build/cythonized/sage/cpython/getattr.c:2614)()
    392         dummy_error_message.cls = type(self)
    393         dummy_error_message.name = name
--> 394         raise AttributeError(dummy_error_message)
    395     attribute = <object>attr
    396     # Check for a descriptor (__get__ in Python)

AttributeError: 'sage.symbolic.expression.Expression' object has no attribute 'iz_zero'
sage: (pi/sqrt(2))*QQbar(sqrt(2))==pi
0.7071067811865475?*sqrt(2)*pi == pi
sage: bool((pi/sqrt(2))*QQbar(sqrt(2))==pi)
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/interface.py in __init__(self, parent, value, is_name, name)
    707             try:
--> 708                 self._name = parent._create(value, name=name)
    709             except (TypeError, RuntimeError, ValueError) as x:

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/maxima_lib.py in _create(self, value, name)
    605             else:
--> 606                 self.set(name, value)
    607         except RuntimeError as error:

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/maxima_lib.py in set(self, var, value)
    514         cmd = '%s : %s$'%(var, value.rstrip(';'))
--> 515         self.eval(cmd)
    516 

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/maxima_lib.py in _eval_line(self, line, locals, reformat, **kwds)
    460                 if statement:
--> 461                     maxima_eval("#$%s$" % statement)
    462         if not reformat:

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/libs/ecl.pyx in sage.libs.ecl.EclObject.__call__ (build/cythonized/sage/libs/ecl.c:7779)()
    804         """
--> 805         lispargs = EclObject(list(args))
    806         return ecl_wrap(ecl_safe_apply(self.obj,(<EclObject>lispargs).obj))

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/libs/ecl.pyx in sage.libs.ecl.EclObject.__init__ (build/cythonized/sage/libs/ecl.c:7313)()
    669         if len(args) != 0:
--> 670             self.set_obj(python_to_ecl(args[0]))
    671 

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/libs/ecl.pyx in sage.libs.ecl.python_to_ecl (build/cythonized/sage/libs/ecl.c:6357)()
    484         else:
--> 485             L=cl_cons(python_to_ecl(pyobj[0]),Cnil)
    486             ptr=L

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/libs/ecl.pyx in sage.libs.ecl.python_to_ecl (build/cythonized/sage/libs/ecl.c:6051)()
    465         s=str_to_bytes(pyobj)
--> 466         return ecl_safe_read_string(s)
    467     elif isinstance(pyobj,bytes):

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/libs/ecl.pyx in sage.libs.ecl.ecl_safe_read_string (build/cythonized/sage/libs/ecl.c:5530)()
    385     o = ecl_cstring_to_base_string_or_nil(s)
--> 386     o = ecl_safe_funcall(read_from_string_clobj,o)
    387     return o

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/libs/ecl.pyx in sage.libs.ecl.ecl_safe_funcall (build/cythonized/sage/libs/ecl.c:5297)()
    364         s = si_coerce_to_base_string(ecl_values(1))
--> 365         raise RuntimeError("ECL says: {}".format(
    366             char_to_str(ecl_base_string_pointer_safe(s))))

RuntimeError: ECL says: THROW: The catch MACSYMA-QUIT is undefined.

During handling of the above exception, another exception occurred:

TypeError                                 Traceback (most recent call last)
<ipython-input-31-93eb451d56f1> in <module>()
----> 1 bool((pi/sqrt(Integer(2)))*QQbar(sqrt(Integer(2)))==pi)

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/symbolic/expression.pyx in sage.symbolic.expression.Expression.__nonzero__ (build/cythonized/sage/symbolic/expression.cpp:19521)()
   2918             # lot of basic Sage objects can't be put into maxima.
   2919             from sage.symbolic.relation import test_relation_maxima
-> 2920             return test_relation_maxima(self)
   2921 
   2922         self_is_zero = self._gobj.is_zero()

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/symbolic/relation.py in test_relation_maxima(relation)
    490         [k is noninteger]
    491     """
--> 492     m = relation._maxima_()
    493 
    494     #Handle some basic cases first

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/symbolic/expression.pyx in sage.symbolic.expression.Expression._maxima_ (build/cythonized/sage/symbolic/expression.cpp:7806)()
    813             # Maybe not such a great idea because the "default" interface is another one
    814             from sage.calculus.calculus import maxima
--> 815             return super(Expression, self)._interface_(maxima)
    816         else:
    817             return super(Expression, self)._interface_(session)

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/structure/sage_object.pyx in sage.structure.sage_object.SageObject._interface_ (build/cythonized/sage/structure/sage_object.c:5532)()
    674             except Exception:
    675                 raise NotImplementedError("coercion of object %s to %s not implemented:\n%s\n%s" % (repr(self), I))
--> 676         X = I(s)
    677         if c:
    678             try:

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/interface.py in __call__(self, x, name)
    286 
    287         if isinstance(x, string_types):
--> 288             return cls(self, x, name=name)
    289         try:
    290             # Special methods do not and should not have an option to

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/interfaces/interface.py in __init__(self, parent, value, is_name, name)
    708                 self._name = parent._create(value, name=name)
    709             except (TypeError, RuntimeError, ValueError) as x:
--> 710                 raise TypeError(x)
    711 
    712     def _latex_(self):

TypeError: ECL says: THROW: The catch MACSYMA-QUIT is undefined.

I would suggest to use this - and I think that the current interface does use this information quite a lot.

But not always wisely, as demonstrated above...

In FriCAS, every object *must* have a proper type. There is no way you can invert a square array of integers. (FriCAS is not very strict about itself, so you may find lots of counterexamples.)

Agreed.

comment:17 Changed 2 years ago by mantepse

Could you please expand on

But by converting SR(2) to QQbar(2), you lose information.

What information do you lose? (Possibly, you would loose information when converting to FriCAS AlgebraicNumber?, because the latter only remembers the minimal polynomial, I think.)

Also, whot is iz_zero?

comment:18 in reply to: ↑ 16 ; follow-up: Changed 2 years ago by mantepse

Replying to charpent:

Isn't the problem with the above failures that the SR and QQbar do not interact nicely? ((pi/sqrt(2))*QQbar(sqrt(2))-pi).is_zero() has nothing to do with the FriCAS interface, as far as I can see.

comment:19 in reply to: ↑ 18 ; follow-up: Changed 2 years ago by charpent

Replying to mantepse:

Replying to charpent:

Isn't the problem with the above failures that the SR and QQbar do not interact nicely?

Yes, indeed. And that's the very reason why returning something "that won't play nice with SR from a call to integrate (which expects symbolic arguments and is expected to return a symbolic expression) is a really dumb idea, notwithstanding the respective virtues of SR and QQbar.

Got it, now ?

((pi/sqrt(2))*QQbar(sqrt(2))-pi).is_zero() has nothing to do with the FriCAS interface, as far as I can see.

I was typing (stupidly) from (muscle) memory. My apologies. Try bool((pi/sqrt(2))*QQbar(sqrt(2)) ==pi) instead... or one of the previous counterexamples.

The root of the problem is that a lot of pur symbolics derive from maxima, which has nothing like QQbar. In fact, maxima(QQbar(sqrt(2))) never returns (but you can interrupt it and return to Sage's prompt).

To drive my point home once more:

sage: f=x*sqrt(2)
sage: [w for w in map(lambda u,v:bool(u==v), f.operands(), f.integrate(x).diff(x)
....: .operands())]
[True, True]
sage: f=x*QQbar(sqrt(2))
sage: [w for w in map(lambda u,v:bool(u==v), f.operands(), f.integrate(x).diff(x)
....: .operands())]
[True, False]

Whatever may be the virtues of QQbar, this is not acceptable.

comment:20 in reply to: ↑ 19 ; follow-up: Changed 2 years ago by charpent

Replying to charpent:

[ Snip... ]

And, in the current state of the patch :

sage: f=x*sqrt(2)
sage: [w for w in map(lambda u,v:bool(u==v), f.operands(), f.integrate(x).diff(x)
....: .operands())]
[True, True]
sage: [w for w in map(lambda u,v:bool(u==v), f.operands(), f.integrate(x, algorit
....: hm="fricas").diff(x).operands())]
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-61-120730aa9cd9> in <module>()
----> 1 [w for w in map(lambda u,v:bool(u==v), f.operands(), f.integrate(x, algorithm="fricas").diff(x).operands())]

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/structure/element.pyx in sage.structure.element.Element.__getattr__ (build/cythonized/sage/structure/element.c:4608)()
    487             AttributeError: 'LeftZeroSemigroup_with_category.element_class' object has no attribute 'blah_blah'
    488         """
--> 489         return self.getattr_from_category(name)
    490 
    491     cdef getattr_from_category(self, name):

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/structure/element.pyx in sage.structure.element.Element.getattr_from_category (build/cythonized/sage/structure/element.c:4717)()
    500         else:
    501             cls = P._abstract_element_class
--> 502         return getattr_from_other_class(self, cls, name)
    503 
    504     def __dir__(self):

/usr/local/sage-P3-2/local/lib/python3.7/site-packages/sage/cpython/getattr.pyx in sage.cpython.getattr.getattr_from_other_class (build/cythonized/sage/cpython/getattr.c:2547)()
    387         dummy_error_message.cls = type(self)
    388         dummy_error_message.name = name
--> 389         raise AttributeError(dummy_error_message)
    390     cdef PyObject* attr = instance_getattr(cls, name)
    391     if attr is NULL:

AttributeError: 'PolynomialRing_field_with_category.element_class' object has no attribute 'operands'

Even less acceptable..

comment:21 in reply to: ↑ 20 Changed 2 years ago by charpent

Replying to charpent:

If the previeous points weren't enough, please explain this inconsistency:

sage: f=sqrt(2)*x
sage: f.integrate(x, algorithm="fricas").diff(x)
1.414213562373095?*x
sage: f=sqrt(2)*x+sin(x)
sage: f.integrate(x, algorithm="fricas").diff(x)
sqrt(2)*x + sin(x)

Am I clear, now ?

comment:22 Changed 2 years ago by mantepse

English is not my native language, but I think "dumb idea" is pretty clear. Could you please tone down?

Apart from that: the general FriCAS interface (and thus conversion of FriCAS polynomials to sage polynomials) and the special integration interface to FriCAS are quite separate. I agree that, when asking FriCAS to integrate something, we should send a symbolic expression - and convert it to Expression Integer.

That's actually what I suggested with

sage: fricas("sqrt(2)::EXPR INT").domainOf()
Expression(Integer())

comment:23 Changed 2 years ago by mantepse

Below is a complementary patch, which (hopefully) makes sure that the FriCAS domain of Symbolic Ring objects is Expression Integer.

This patch does neither solve the polynomial conversion problem, nor conversion from QQbar to FriCAS' AlgebraicNumber.

  • src/sage/symbolic/expression_conversions.py

    index ad2e20a..c491b44 100644
    a b class FriCASConverter(InterfaceInit): 
    898898        import sage.interfaces.fricas
    899899        super(FriCASConverter, self).__init__(sage.interfaces.fricas.fricas)
    900900
     901    def pyobject(self, ex, obj):
     902        """
     903        EXAMPLES::
     904
     905            sage: 2._fricas_().domainOf()                                       # optional - fricas
     906            PositiveInteger()
     907
     908            sage: (-1/2)._fricas_().domainOf()                                  # optional - fricas
     909            Fraction(Integer())
     910
     911            sage: SR(2)._fricas_().domainOf()                                   # optional - fricas
     912            Expression(Integer())
     913
     914            sage: (sqrt(2))._fricas_().domainOf()                               # optional - fricas
     915            Expression(Integer())
     916        """
     917        return "((%s)::EXPR INT)" % ex
     918
     919    def symbol(self, ex):
     920        """
     921        EXAMPLES::
     922
     923            sage: x._fricas_().domainOf()                                       # optional - fricas
     924            Expression(Integer())
     925        """
     926        return "(%s::EXPR INT)" % repr(ex)
     927
    901928    def derivative(self, ex, operator):
    902929        """
    903930        Convert the derivative of ``self`` in FriCAS.
  • src/sage/symbolic/integration/external.py

    diff --git a/src/sage/symbolic/integration/external.py b/src/sage/symbolic/integration/external.py
    index 057b113..c116536 100644
    a b def fricas_integrator(expression, v, a=None, b=None, noPole=True): 
    371371
    372372    Check that in case of failure one gets unevaluated integral::
    373373
    374         sage: integral(cos(ln(cos(x))), x, 0, pi/8, algorithm='fricas')   # optional - fricas
     374        sage: integral(cos(ln(cos(x))), x, 0, pi/8, algorithm='fricas')         # optional - fricas
    375375        integrate(cos(log(cos(x))), x, 0, 1/8*pi)
    376         sage: integral(cos(ln(cos(x))), x, algorithm='fricas')   # optional - fricas
     376
     377        sage: integral(cos(ln(cos(x))), x, algorithm='fricas')                  # optional - fricas
    377378        integral(cos(log(cos(x))), x)
     379
     380    Check that :trac:`28641` is fixed::
     381
     382        sage: integrate(sqrt(2)*x^2 + 2*x, x, algorithm="fricas")               # optional - fricas
     383        1/3*sqrt(2)*x^3 + x^2
     384
     385        sage: integrate(sqrt(2), x, algorithm="fricas")                         # optional - fricas
     386        sqrt(2)*x
     387
     388        sage: integrate(1, x, algorithm="fricas")                               # optional - fricas
     389        x
    378390    """
    379391    if not isinstance(expression, Expression):
    380392        expression = SR(expression)
    381393
    382394    from sage.interfaces.fricas import fricas
    383395    ex = fricas(expression)
     396    v = fricas("%s::Symbol" % v)
    384397
    385398    if a is None:
    386399        result = ex.integrate(v)

comment:24 Changed 2 years ago by mantepse

ping?

comment:25 Changed 2 years ago by chapoton

please make a branch, not a patch

comment:26 Changed 2 years ago by mantepse

OK - I'll open a separate ticket, because the branch in this ticket is (despite the problem it fixes) about polynomial conversion.

comment:27 Changed 2 years ago by tmonteil

Possible collision with #28647 which refers to the same ask.sagemath.org question.

comment:28 Changed 22 months ago by embray

  • Milestone changed from sage-9.0 to sage-9.1

Ticket retargeted after milestone closed

comment:29 Changed 19 months ago by mkoeppe

  • Milestone changed from sage-9.1 to sage-9.2

Batch modifying tickets that will likely not be ready for 9.1, based on a review of the ticket title, branch/review status, and last modification date.

comment:30 Changed 14 months ago by mkoeppe

  • Milestone changed from sage-9.2 to sage-9.3

comment:31 Changed 9 months ago by mkoeppe

  • Milestone changed from sage-9.3 to sage-9.4

Setting new milestone based on a cursory review of ticket status, priority, and last modification date.

comment:32 Changed 4 months ago by chapoton

  • Milestone changed from sage-9.4 to sage-duplicate/invalid/wontfix
  • Status changed from needs_work to needs_review

maybe we can close as duplicate ?

comment:33 Changed 2 months ago by chapoton

  • Branch u/chapoton/28641 deleted
  • Commit 0bf95407d96a15022e458aea53cd861d830c3fb5 deleted

ping ? Martin, can we close ?

comment:34 Changed 2 months ago by mantepse

  • Status changed from needs_review to positive_review

OK.

comment:35 Changed 2 months ago by chapoton

  • Resolution set to invalid
  • Status changed from positive_review to closed
Note: See TracTickets for help on using tickets.