# HG changeset patch
# User William Stein <wstein@gmail.com>
# Date 1184619220 25200
# Node ID 3716d2872ec7bf0adb8850d959bee13b82f9f414
# Parent  27c64e5a8c14a90a19b53a1bfb87f60e4bd0eb26
Arithmetic with symbolic equations and inequalities; n as shortcut for numerical_approx.

diff -r 27c64e5a8c14 -r 3716d2872ec7 sage/calculus/calculus.py
--- a/sage/calculus/calculus.py	Wed Jul 11 14:19:57 2007 -0700
+++ b/sage/calculus/calculus.py	Mon Jul 16 13:53:40 2007 -0700
@@ -723,9 +723,12 @@ class SymbolicExpression(RingElement):
         return long(int(self))
 
     def numerical_approx(self, prec=53):
-        """
+        r"""
         Return a numerical approximation of self as either a real or
         complex number.
+
+        NOTE: You can use \code{foo.n()} as a shortcut for
+        \code{foo.numerical_approx()}.
 
         INPUT:
             prec -- integer (default: 53): the number of bits of precision
@@ -737,6 +740,12 @@ class SymbolicExpression(RingElement):
         EXAMPLES:
             sage: cos(3).numerical_approx()
             -0.989992496600445
+
+        Use the n() shortcut:
+            sage: cos(3).n()
+            -0.989992496600445
+
+        Higher precision:
             sage: cos(3).numerical_approx(200)
             -0.98999249660044545727157279473126130239367909661558832881409
             sage: (i + 1).numerical_approx(32)
@@ -755,6 +764,8 @@ class SymbolicExpression(RingElement):
             approx = self._complex_mpfr_field_(ComplexField(prec))
 
         return approx
+
+    n = numerical_approx
 
     def _mpfr_(self, field):
         raise TypeError
diff -r 27c64e5a8c14 -r 3716d2872ec7 sage/calculus/equations.py
--- a/sage/calculus/equations.py	Wed Jul 11 14:19:57 2007 -0700
+++ b/sage/calculus/equations.py	Mon Jul 16 13:53:40 2007 -0700
@@ -4,6 +4,7 @@ SAGE can solving symbolic equations and 
 SAGE can solving symbolic equations and expressing inequalities.
 For example, we derive the quadratic formula as follows:
 
+    sage: a,b,c = var('a,b,c')
     sage: qe = (a*x^2 + b*x + c == 0)
     sage: print qe
                                      2
@@ -23,15 +24,42 @@ AUTHORS:
 AUTHORS:
     -- Bobby Moretti: initial version
     -- William Stein: second version
+    -- William Stein (2007-07-16): added arithmetic with symbolic equations
 
 EXAMPLES:
+    sage: x,y,a = var('x,y,a')
     sage: f = x^2 + y^2 == 1
     sage: f.solve(x)
-    [x == (-sqrt(1 - y^2)), x == sqrt(1 - y^2)]
+    [x == -sqrt(1 - y^2), x == sqrt(1 - y^2)]
 
     sage: f = x^5 + a
     sage: solve(f==0,x)
-    [x == -e^(2*I*pi/5)*a^(1/5), x == -e^(4*I*pi/5)*a^(1/5), x == -e^(-(4*I*pi/5))*a^(1/5), x == -e^(-(2*I*pi/5))*a^(1/5), x == (-a^(1/5))]
+    [x == -e^(2*I*pi/5)*a^(1/5), x == -e^(4*I*pi/5)*a^(1/5), x == -e^(-(4*I*pi/5))*a^(1/5), x == -e^(-(2*I*pi/5))*a^(1/5), x == -a^(1/5)]
+
+
+You can also do arithmetic with inequalities, as illustrated below:
+    sage: var('x y')
+    (x, y)
+    sage: f = x + 3 == y - 2
+    sage: f
+    x + 3 == y - 2
+    sage: g = f - 3; g
+    x == y - 5
+    sage: h =  x^3 + sqrt(2) == x*y*sin(x)
+    sage: h
+    x^3 + sqrt(2) == x*sin(x)*y
+    sage: h - sqrt(2)
+    x^3 == x*sin(x)*y - sqrt(2)
+    sage: h + f
+    x^3 + x + sqrt(2) + 3 == x*sin(x)*y + y - 2
+    sage: f = x + 3 < y - 2
+    sage: g = 2 < x+10
+    sage: f - g
+    x + 1 < y - x - 12
+    sage: f + g
+    x + 5 < y + x + 8
+    sage: f*(-1)
+    -x - 3 > 2 - y
 """
 
 _assumptions = []
@@ -60,14 +88,19 @@ comparisons = {operator.lt:set([-1]), op
 comparisons = {operator.lt:set([-1]), operator.le:set([-1,0]), operator.eq:set([0]),
                operator.ne:set([-1,1]),  operator.ge:set([0,1]), operator.gt:set([1])}
 
+opposite_op = {operator.lt:operator.gt, operator.le:operator.ge,
+               operator.ne:operator.ne, operator.eq:operator.eq,
+               operator.gt: operator.lt, operator.ge:operator.le}
+
 def var_cmp(x,y):
     return cmp(str(x), str(y))
 
 def paren(x):
-    if x._is_atomic():
-        return repr(x)
+    r = repr(x)
+    if x._is_atomic() or not ('+' in r or '-' in r):
+        return r
     else:
-        return '(%s)'%repr(x)
+        return '(%s)'%r
 
 class SymbolicEquation(SageObject):
     def __init__(self, left, right, op):
@@ -80,6 +113,249 @@ class SymbolicEquation(SageObject):
 
     def __getitem__(self, i):
         return [self._left, self._op, self._right][i]
+
+    def _scalar(self, scalar, op):
+        """
+        TESTS:
+            sage: var('x y')
+            (x, y)
+            sage: f = x + 3 < y - 2
+            sage: f*-1
+            -x - 3 > 2 - y
+            sage: f * 5
+            5*(x + 3) < 5*(y - 2)
+            sage: f - 3
+            x < y - 5
+            sage: f + 2
+            x + 5 < y
+        """
+        SR = self._left.parent()
+        x = SR(scalar)
+
+        # There are no subtleties if both sides are equal or
+        # we are adding or subtracting from both sides. 
+        if self._op == operator.eq or op in [operator.add, operator.sub]:
+            return SymbolicEquation(op(self._left, x),
+                                    op(self._right, x),
+                                    self._op)
+
+        # Now we are multiplying both sides by a scalar and we have an inequality, i.e.,
+        # one of <, <=, >=, > or !=.
+        if x == 0:
+            return SymbolicEquation(SR(0), SR(0), operator.eq)
+        elif x > 0:
+            return SymbolicEquation(op(self._left, x), op(self._right, x), self._op)
+        elif x < 0:
+            # Now we are multiplying or dividing both sides by a negative number.
+            op2 = opposite_op[self._op]
+            return SymbolicEquation(op(self._left, x), op(self._right, x), op2)
+        else:
+            raise ValueError, "unable to multiply or divide both sides of an inequality by a number whose sign can't be determined."
+
+    def multiply_both_sides(self, x):
+        """
+        Multiply both sides of this inequality by x.
+
+        EXAMPLES:
+            sage: var('x,y'); f = x + 3 < y - 2
+            (x, y)
+            sage: f.multiply_both_sides(7)
+            7*(x + 3) < 7*(y - 2)
+            sage: f.multiply_both_sides(-1/2)
+            (-x - 3)/2 > (2 - y)/2        
+            sage: f*(-2/3)
+            -2*(x + 3)/3 > -2*(y - 2)/3
+            sage: f*(-pi)
+            -1*pi*(x + 3) > -1*pi*(y - 2)
+            sage: f*(1+I)
+            Traceback (most recent call last):
+            ...
+            ValueError: unable to multiply or divide both sides of an inequality by a number whose sign can't be determined.
+
+        Multiplying by complex numbers works only if its an inequality:
+            sage: f = sqrt(2) + x == y^3
+            sage: f.multiply_both_sides(I)
+            I*(x + sqrt(2)) == I*y^3
+            sage: f.multiply_both_sides(-1)
+            -x - sqrt(2) == -y^3
+
+        Some further examples:
+            sage: (x^3 + 1 > 2*sqrt(3)) * (-1)
+            -x^3 - 1 < -2*sqrt(3)
+            sage: (x^3 + 1 >= 2*sqrt(3)) * (-1)
+            -x^3 - 1 <= -2*sqrt(3)
+            sage: (x^3 + 1 <= 2*sqrt(3)) * (-1)
+            -x^3 - 1 >= -2*sqrt(3)        
+        """
+        return self._scalar(x, operator.mul)
+
+    def divide_both_sides(self, x):
+        """
+        Divide both sides of the inequality by x.
+
+        EXAMPLES:
+            sage: (x^3 + 1 > x^2 - 1) / (-1)
+            -x^3 - 1 < 1 - x^2
+
+        The quantity $x^2 - 1$ could be either negative or positive depending on $x$, so
+        dividing by it is not defined.
+            sage: (x^3 + 1 > x^2 - 1) / (x^2 - 1)
+            Traceback (most recent call last):
+            ...
+            ValueError: unable to multiply or divide both sides of an inequality by a number whose sign can't be determined.
+
+        If we specify that $x^2 - 1> 0$, then dividing is defined. 
+            sage: assume(x^2 - 1 > 0)
+            sage: (x^3 + 1 > x^2 - 1) / (x^2 - 1)
+            (x^3 + 1)/(x^2 - 1) > 1
+            sage: forget()
+
+        We can also specify that $x^2 - 1 < 0$.  Note that now the inequality direction changes. 
+            sage: assume(x^2 - 1 < 0)
+            sage: (x^3 + 1 > x^2 - 1) / (x^2 - 1)
+            (x^3 + 1)/(x^2 - 1) < 1
+            sage: forget()            
+        """
+        return self._scalar(x, operator.div)
+
+    def add_to_both_sides(self, x):
+        """
+        Add x to both sides of this symbolic equation.
+
+        EXAMPLES:
+            sage: var('x y z')
+            (x, y, z)
+            sage: eqn = x^2 + y^2 + z^2 <= 1
+            sage: eqn.add_to_both_sides(-z^2)
+            y^2 + x^2 <= 1 - z^2
+            sage: eqn.add_to_both_sides(I)
+            z^2 + y^2 + x^2 + I <= I + 1            
+        """
+        return self._scalar(x, operator.add)
+
+    def subtract_from_both_sides(self, x):
+        """
+        Subtract x from both sides of this symbolic equation.
+
+        EXAMPLES:
+            sage: eqn = x*sin(x)*sqrt(3) + sqrt(2) > cos(sin(x))
+            sage: eqn.subtract_from_both_sides(sqrt(2))
+            sqrt(3)*x*sin(x) > cos(sin(x)) - sqrt(2)
+            sage: eqn.subtract_from_both_sides(cos(sin(x)))
+            -cos(sin(x)) + sqrt(3)*x*sin(x) + sqrt(2) > 0        
+        """
+        return self._scalar(x, operator.sub)
+
+    def _arith(self, right, op):
+        if not isinstance(right, SymbolicEquation):
+            return self._scalar(right, op)
+                
+        if self._op != right._op:
+            raise ValueError, "can only do arithmetic with symbolic equations with the same equality or inequality"
+
+        if not (op in [operator.add, operator.sub]):
+            if not (self._op in [operator.eq, operator.ne]):
+                raise ValueError, "cannot multiply or divide inequalities."
+
+        return SymbolicEquation(op(self._left, right._left),
+                                op(self._right, right._right),
+                                self._op)
+            
+    def __add__(self, right):
+        """
+        Add two symbolic equations.
+
+        EXAMPLES:
+            sage: var('a,b')
+            (a, b)
+            sage: m = 144 == -10 * a + b
+            sage: n = 136 == 10 * a + b
+            sage: m + n
+            280 == 2*b        
+        """
+        return self._arith(right, operator.add)
+
+    def __radd__(self, left):
+        """
+        Add two symbolic equations.
+
+        EXAMPLES:
+            sage: var('a,b')
+            (a, b)            
+            sage: m = 144 == -10 * a + b
+            sage: n = 136 == 10 * a + b
+            sage: int(-144) + m
+            0 == b - 10*a - 144        
+        """
+        # ok to use this, since everything is commutative in the symbolic ring.
+        return self._arith(left, operator.add)
+
+    def __sub__(self, right):
+        """
+        Subtract two symbolic equations.
+
+        EXAMPLES:
+            sage: var('a,b')
+            (a, b)            
+            sage: m = 144 == 20 * a + b
+            sage: n = 136 == 10 * a + b
+            sage: m - n
+            8 == 10*a        
+        """
+        return self._arith(right, operator.sub)
+            
+    def __rsub__(self, left):
+        """
+        Subtract two symbolic equations.
+
+        EXAMPLES:
+            sage: var('a,b')
+            (a, b)
+            sage: m = 144 == -10 * a + b
+            sage: n = 136 == 10 * a + b
+            sage: int(144) - m
+            0 == b - 10*a - 144        
+        """
+        # ok to use this, since everything is commutative in the symbolic ring.
+        return self._arith(left, operator.sub)
+
+    def __mul__(self, right):
+        """
+        Multiply two symbolic equations.
+
+        EXAMPLES:
+            sage: m = x == 5*x + 1
+            sage: n = sin(x) == sin(x+2*pi)
+            sage: m * n
+            x*sin(x) == (5*x + 1)*sin(x)        
+        """
+        return self._arith(right, operator.mul)
+
+    def __rmul__(self, left):
+        """
+        Multiply two symbolic equations.
+            sage: m = 2*x == 3*x^2 - 5
+            sage: int(-1) * m
+            -2*x == 5 - 3*x^2        
+        """
+        return self._arith(left, operator.mul)
+
+    def __div__(self, right):
+        """
+        Divide two symbolic equations.
+
+        EXAMPLES:
+            sage: m = x == 5*x + 1
+            sage: n = sin(x) == sin(x+2*pi)
+            sage: m / n
+            x/sin(x) == (5*x + 1)/sin(x)
+            sage: m = x != 5*x + 1
+            sage: n = sin(x) != sin(x+2*pi)
+            sage: m / n
+            x/sin(x) != (5*x + 1)/sin(x)        
+        """
+        return self._arith(right, operator.div)
+
 
     # The maxima one is special:
     def _maxima_(self, session=None):
@@ -114,13 +390,15 @@ class SymbolicEquation(SageObject):
         return 0
 
     def _repr_(self):
-        return "%s%s%s" %(paren(self._left), symbols[self._op], paren(self._right))
+        return "%r%s%r" %(self._left, symbols[self._op], self._right)
 
     def variables(self):
         """
         EXAMPLES:
+            sage: var('x,y,z,w')
+            (x, y, z, w)
             sage: f =  (x+y+w) == (x^2 - y^2 - z^3);   f
-            (y + x + w) == (-z^3 - y^2 + x^2)
+            y + x + w == -z^3 - y^2 + x^2
             sage: f.variables()
             [w, x, y, z]
         """
@@ -150,7 +428,7 @@ class SymbolicEquation(SageObject):
         EXAMPLES:
             sage: f =  (x^2 - x == 0)
             sage: f
-            (x^2 - x) == 0
+            x^2 - x == 0
             sage: print f
                                                2
                                               x  - x == 0
@@ -223,9 +501,9 @@ class SymbolicEquation(SageObject):
         EXAMPLES:
             sage: S = solve(x^3 - 1 == 0, x)
             sage: S
-            [x == ((sqrt(3)*I - 1)/2), x == ((-sqrt(3)*I - 1)/2), x == 1]
+            [x == (sqrt(3)*I - 1)/2, x == (-sqrt(3)*I - 1)/2, x == 1]
             sage: S[0]
-            x == ((sqrt(3)*I - 1)/2)
+            x == (sqrt(3)*I - 1)/2
             sage: S[0].right()
             (sqrt(3)*I - 1)/2
 
@@ -235,8 +513,6 @@ class SymbolicEquation(SageObject):
             [x == -1*I, x == I, x == 1]
             sage: solve(f == 0, x, multiplicities=True)
             ([x == -1*I, x == I, x == 1], [1, 1, 5])
-            sage: solve(g == 0, x)
-            []            
         """
         if not self._op is operator.eq:
             raise ValueError, "solving only implemented for equalities"
@@ -284,12 +560,12 @@ def assume(*args):
         sage: from sage.calculus.calculus import maxima as calcmaxima
         sage: calcmaxima.eval('declare(n,integer)')
         'done'
-        sage: var('r2')
-        r2
+        sage: var('n, P, r, r2')
+        (n, P, r, r2)
         sage: c = P*e^(r*n)
         sage: d = P*(1+r2)^n
         sage: solve(c==d,r2)
-        [r2 == (e^r - 1)]
+        [r2 == e^r - 1]
     """
     for x in args:
         if isinstance(x, (tuple, list)):
@@ -313,6 +589,8 @@ def forget(*args):
 
     EXAMPLES:
     We define and forget multiple assumptions:
+        sage: var('x,y,z')
+        (x, y, z)
         sage: assume(x>0, y>0, z == 1, y>0)
         sage: assumptions()
         [x > 0, y > 0, z == 1]
@@ -338,10 +616,12 @@ def assumptions():
     List all current symbolic assumptions.
     
     EXAMPLES:
+        sage: var('x,y,z, w')
+        (x, y, z, w)
         sage: forget()
         sage: assume(x^2+y^2 > 0)
         sage: assumptions()
-        [(y^2 + x^2) > 0]
+        [y^2 + x^2 > 0]
         sage: forget(x^2+y^2 > 0)
         sage: assumptions()
         []
@@ -375,13 +655,14 @@ def solve(f, *args, **kwds):
         *args -- variables to solve for.
 
     EXAMPLES:
+        sage: x, y = var('x, y')
         sage: solve([x+y==6, x-y==4], x, y)
         [[x == 5, y == 1]]
         sage: solve([x^2+y^2 == 1, y^2 == x^3 + x + 1], x, y)
-        [[x == ((-sqrt(3)*I - 1)/2), y == ((-sqrt(3 - sqrt(3)*I))/sqrt(2))],
-         [x == ((-sqrt(3)*I - 1)/2), y == (sqrt(3 - sqrt(3)*I)/sqrt(2))],
-         [x == ((sqrt(3)*I - 1)/2), y == ((-sqrt(sqrt(3)*I + 3))/sqrt(2))],
-         [x == ((sqrt(3)*I - 1)/2), y == (sqrt(sqrt(3)*I + 3)/sqrt(2))],
+        [[x == (-sqrt(3)*I - 1)/2, y == (-sqrt(3 - sqrt(3)*I))/sqrt(2)],
+         [x == (-sqrt(3)*I - 1)/2, y == sqrt(3 - sqrt(3)*I)/sqrt(2)],
+         [x == (sqrt(3)*I - 1)/2, y == (-sqrt(sqrt(3)*I + 3))/sqrt(2)],
+         [x == (sqrt(3)*I - 1)/2, y == sqrt(sqrt(3)*I + 3)/sqrt(2)],
          [x == 0, y == -1],
          [x == 0, y == 1]]
     """
