Skip to content

Commit

Permalink
Trac #21152: Implement unary operations in interfaces
Browse files Browse the repository at this point in the history
Currently, Sage relies on the default implementations from `RingElement`
for unary operations for interface elements. Instead, we should directly
implement unary operations in `InterfaceElement` analogous to the binary
operations. Maxima already does this.

URL: https://trac.sagemath.org/21152
Reported by: jdemeyer
Ticket author(s): Jeroen Demeyer
Reviewer(s): Travis Scrimshaw
  • Loading branch information
Release Manager authored and vbraun committed Aug 6, 2016
2 parents b55d688 + 12d9d32 commit f57c40a
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 165 deletions.
165 changes: 163 additions & 2 deletions src/sage/interfaces/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -1219,10 +1219,46 @@ def gen(self, n):
P = self._check_valid()
return P.new('%s.%s'%(self._name, int(n)))

def _operation(self, operation, right):
def _operation(self, operation, other=None):
r"""
Return the result of applying the binary operation
``operation`` on the arguments ``self`` and ``other``, or the
unary operation on ``self`` if ``other`` is not given.
This is a utility function which factors out much of the
commonality used in the arithmetic operations for interface
elements.
INPUT:
- ``operation`` -- a string representing the operation
being performed. For example, '*', or '1/'.
- ``other`` -- the other operand. If ``other`` is ``None``,
then the operation is assumed to be unary rather than binary.
OUTPUT: an interface element
EXAMPLES::
sage: a = gp('23')
sage: b = gp('5')
sage: a._operation('%', b)
3
sage: a._operation('19+')
42
sage: a._operation('!@#$%')
Traceback (most recent call last):
...
TypeError: Error executing code in GP:...
"""
P = self._check_valid()
if other is None:
cmd = '%s %s'%(operation, self._name)
else:
cmd = '%s %s %s'%(self._name, operation, other._name)
try:
return P.new('%s %s %s'%(self._name, operation, right._name))
return P.new(cmd)
except Exception as msg:
raise TypeError(msg)

Expand All @@ -1238,6 +1274,31 @@ def _add_(self, right):
cos(_SAGE_VAR_x)+2
sage: 2 + f
cos(_SAGE_VAR_x)+2
::
sage: x,y = var('x,y')
sage: f = maxima.function('x','sin(x)')
sage: g = maxima.function('x','-cos(x)')
sage: f+g
sin(x)-cos(x)
sage: f+3
sin(x)+3
The Maxima variable ``x`` is different from the Sage symbolic variable::
sage: (f+maxima.cos(x))
cos(_SAGE_VAR_x)+sin(x)
sage: (f+maxima.cos(y))
cos(_SAGE_VAR_y)+sin(x)
Note that you may get unexpected results when calling symbolic expressions
and not explicitly giving the variables::
sage: (f+maxima.cos(x))(2)
cos(_SAGE_VAR_x)+sin(2)
sage: (f+maxima.cos(y))(2)
cos(_SAGE_VAR_y)+sin(2)
"""
return self._operation("+", right)

Expand All @@ -1253,9 +1314,42 @@ def _sub_(self, right):
cos(_SAGE_VAR_x)-2
sage: 2 - f
2-cos(_SAGE_VAR_x)
::
sage: x,y = var('x,y')
sage: f = maxima.function('x','sin(x)')
The Maxima variable ``x`` is different from the Sage symbolic variable::
sage: (f-maxima.cos(x))
sin(x)-cos(_SAGE_VAR_x)
sage: (f-maxima.cos(y))
sin(x)-cos(_SAGE_VAR_y)
Note that you may get unexpected results when calling symbolic expressions
and not explicitly giving the variables::
sage: (f-maxima.cos(x))(2)
sin(2)-cos(_SAGE_VAR_x)
sage: (f-maxima.cos(y))(2)
sin(2)-cos(_SAGE_VAR_y)
"""
return self._operation('-', right)

def _neg_(self):
"""
EXAMPLES::
sage: f = maxima('sin(x)')
sage: -f
-sin(x)
sage: f = maxima.function('x','sin(x)')
sage: -f
-sin(x)
"""
return self._operation('-')

def _mul_(self, right):
"""
EXAMPLES::
Expand All @@ -1266,6 +1360,26 @@ def _mul_(self, right):
cos(_SAGE_VAR_x)*sin(_SAGE_VAR_x)
sage: 2*f
2*cos(_SAGE_VAR_x)
::
sage: f = maxima.function('x','sin(x)')
sage: g = maxima('-cos(x)') # not a function!
sage: f*g
-cos(x)*sin(x)
sage: _(2)
-cos(2)*sin(2)
::
sage: f = maxima.function('x','sin(x)')
sage: g = maxima('-cos(x)')
sage: g*f
-cos(x)*sin(x)
sage: _(2)
-cos(2)*sin(2)
sage: 2*f
2*sin(x)
"""
return self._operation('*', right)

Expand All @@ -1279,9 +1393,42 @@ def _div_(self, right):
cos(_SAGE_VAR_x)/sin(_SAGE_VAR_x)
sage: f/2
cos(_SAGE_VAR_x)/2
::
sage: f = maxima.function('x','sin(x)')
sage: g = maxima('-cos(x)')
sage: f/g
-sin(x)/cos(x)
sage: _(2)
-sin(2)/cos(2)
::
sage: f = maxima.function('x','sin(x)')
sage: g = maxima('-cos(x)')
sage: g/f
-cos(x)/sin(x)
sage: _(2)
-cos(2)/sin(2)
sage: 2/f
2/sin(x)
"""
return self._operation("/", right)

def __invert__(self):
"""
EXAMPLES::
sage: f = maxima('sin(x)')
sage: ~f
1/sin(x)
sage: f = maxima.function('x','sin(x)')
sage: ~f
1/sin(x)
"""
return self._operation('1/')

def _mod_(self, right):
"""
EXAMPLES::
Expand All @@ -1300,6 +1447,20 @@ def __pow__(self, n):
sage: a = maxima('2')
sage: a^(3/4)
2^(3/4)
::
sage: f = maxima.function('x','sin(x)')
sage: g = maxima('-cos(x)')
sage: f^g
1/sin(x)^cos(x)
::
sage: f = maxima.function('x','sin(x)')
sage: g = maxima('-cos(x)') # not a function
sage: g^f
(-cos(x))^sin(x)
"""
P = self._check_valid()
if parent(n) is not P:
Expand Down
Loading

0 comments on commit f57c40a

Please sign in to comment.