Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
Build symbolic expression from descriptor graph of algebraic number.
Browse files Browse the repository at this point in the history
The current state of affairs is probably going too far: we manage to
construct symbolic expressions for many algebraic numbers, even if there was
absolutely no symbolic expression involved in the input.  In many cases,
the resulting exactification is different from what had been used so far.
For this reason, many doctests in qqbar (and likely other places as well)
currently FAIL.  Some of the discrepancies are for the better, though.
We have yet to decide where to draw the line, when to go via symbolic
expressions and when not to.
  • Loading branch information
gagern committed Apr 3, 2015
1 parent f065ca4 commit 8cc7bc7
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 8 deletions.
134 changes: 127 additions & 7 deletions src/sage/rings/qqbar.py
Expand Up @@ -3088,6 +3088,36 @@ def norm(self, n):
else:
return (n*n)._descr

def quick_symbolic(self):
r"""
A symbolic representation for this number, if quickly available.
If this descriptor is the result of converting a symbolic
expression to an algebraic number, that symbolic expression is
stored and hence available. Combining such numbers with other
such numbers or rational numbers, using only elementary
arithmetic operations, makes a symbolic expression for the
final result available as well.
The function :func:`sage.symbolic.expression_conversions.algebraic`
will overwrite this method by a function which simply returns
the symbolic expression that led to that algebraic number.
So if the input is a symbolic expression, this is a shortcut.
EXAMPLE::
sage: a = QQbar(sqrt(2))
sage: b = a._descr
sage: b.quick_symbolic()
sqrt(2)
sage: p = QQ['x']([1,5,3])
sage: a = p.roots(QQbar, multiplicities=False)[0]
sage: b = a._descr
sage: b.quick_symbolic() is None
True
"""
return None

class AlgebraicNumber_base(sage.structure.element.FieldElement):
r"""
This is the common base class for algebraic numbers (complex
Expand Down Expand Up @@ -3651,8 +3681,7 @@ def exactify(self):
"""
od = self._descr
if od.is_exact(): return
if self._symbolic_expression is not None:
self._exact_symbolic()
self._exact_symbolic()
self._set_descr(self._descr.exactify())

def _set_descr(self, new_descr):
Expand All @@ -3679,8 +3708,6 @@ def _set_descr(self, new_descr):
else:
self._value = self._value.intersection(new_val)

_symbolic_expression = None

def _exact_symbolic(self):
r"""
Compute an exact representation of self using a known symbolic expression.
Expand All @@ -3698,13 +3725,16 @@ def _exact_symbolic(self):
sage: c.minpoly() # indirect doctest
x^6 - 49/2*x^4 + 133/16*x^2 + 225/4
"""

e = self._descr.quick_symbolic()
if e is None:
return
try:
# Only numeric conversion is faster; algebraic would cause infinite recursion.
p = self._symbolic_expression.minpoly(algorithm='numeric')
p = e.minpoly(algorithm='numeric')
except (NotImplementedError, ValueError):
return
r = p.roots(self.parent(), False)
K = QQbar if is_ComplexIntervalFieldElement(self._value) else AA
r = p.roots(K, multiplicities=False)
r = [z for z in r if z._value.overlaps(self._value)]
while len(r) > 1:
# TODO: find input which actually tests this code path!
Expand Down Expand Up @@ -5622,6 +5652,21 @@ def scale(self):
"""
return self._value

def quick_symbolic(self):
r"""
Cast this rational number to a symbolic expression.
EXAMPLE::
sage: a = QQbar(5/7)._descr.quick_symbolic()
sage: a
5/7
sage: a.parent()
Symbolic Ring
"""
from sage.symbolic.ring import SR
return SR(self._value)

class ANRootOfUnity(ANDescr):
r"""
The subclass of ``ANDescr`` that represents a rational multiplied
Expand Down Expand Up @@ -6027,6 +6072,21 @@ def scale(self):
"""
return self._scale

def quick_symbolic(self):
r"""
Cast this root of unity to a symbolic expression.
EXAMPLE::
sage: a = (3*QQbar.zeta(5)^2)._descr.quick_symbolic()
sage: a
3*e^(4/5*I*pi)
sage: a.parent()
Symbolic Ring
"""
from sage.all import exp, I, pi
return self._scale * exp(2*I*pi * self._angle)

def is_AlgebraicReal(x):
r"""
Test if ``x`` is an instance of :class:`~AlgebraicReal`. For internal use.
Expand Down Expand Up @@ -7814,6 +7874,37 @@ def exactify(self):
arg.exactify()
return arg._descr.conjugate(None)

def quick_symbolic(self):
r"""
Apply this operation to the symbolic expression of its argument.
EXAMPLE::
sage: v = (-QQbar(sqrt(2)))._descr
sage: type(v)
<class 'sage.rings.qqbar.ANUnaryExpr'>
sage: v.quick_symbolic()
-sqrt(2)
"""
arg = self._arg._descr.quick_symbolic()
if arg is None:
return None
op = self._op
if op == '-':
return -arg
if op == '~':
return 1/arg
if op == 'real':
return arg.real()
if op == 'imag':
return arg.imag()
if op == 'abs':
return arg.abs()
if op == 'norm':
return arg * arg.conjugate()
if op == 'conjugate':
return arg.conjugate()

class ANBinaryExpr(ANDescr):
def __init__(self, left, right, op):
r"""
Expand Down Expand Up @@ -8054,6 +8145,35 @@ def exactify(self):
finally:
sys.setrecursionlimit(old_recursion_limit)

def quick_symbolic(self):
r"""
Apply this operation to the symbolic expression of its argument.
EXAMPLE::
sage: a = QQbar.zeta(3) + AA(sqrt(2))
sage: b = a._descr
sage: type(b)
<class 'sage.rings.qqbar.ANBinaryExpr'>
sage: b.quick_symbolic()
sqrt(2) + e^(2/3*I*pi)
"""
left = self._left._descr.quick_symbolic()
if left is None:
return None
right = self._right._descr.quick_symbolic()
if right is None:
return None
op = self._op
if op == '+':
return left + right
if op == '-':
return left - right
if op == '*':
return left * right
if op == '/':
return left / right

ax = QQbarPoly.gen()
# def heptadecagon():
# # Compute the exact (x,y) coordinates of the vertices of a 34-gon.
Expand Down
2 changes: 1 addition & 1 deletion src/sage/symbolic/expression_conversions.py
Expand Up @@ -942,7 +942,7 @@ def algebraic(ex, field):
0
"""
res = AlgebraicConverter(field)(ex)
res._symbolic_expression = ex
res._descr.quick_symbolic = lambda: ex
return res

##############
Expand Down

0 comments on commit 8cc7bc7

Please sign in to comment.