# HG changeset patch
# User Jason Grout <jason-sage@creativetrax.com>
# Date 1272945397 18000
# Node ID 40d5603e67a9a1b7d729c1565b7c1f3b996527c4
# Parent  5db30cfa5ba1ac38cdc23c9c348749a34586a45c
Make the preparser understand vector-valued functions, and add differentiating ability to the vectors and matrices.

diff -r 5db30cfa5ba1 -r 40d5603e67a9 sage/calculus/all.py
--- a/sage/calculus/all.py	Mon May 03 10:53:32 2010 -0700
+++ b/sage/calculus/all.py	Mon May 03 22:56:37 2010 -0500
@@ -18,9 +18,11 @@
 
 from interpolators import polygon_spline, complex_cubic_spline
 
+from sage.modules.all import vector
+
 def symbolic_expression(x):
     """
-    Create a symbolic expression from x.
+    Create a symbolic expression or vector of symbolic expressions from x.
 
     INPUT:
 
@@ -57,7 +59,28 @@
         sage: symbolic_expression(E)
         x*y + y^2 + y == x^3 + x^2 - 10*x - 10
         sage: symbolic_expression(E) in SR
-        True 
+        True         
+        
+    If x is a list or tuple, create a vector of symbolic expressions::
+    
+        sage: v=symbolic_expression([x,1]); v
+        (x, 1)
+        sage: v.base_ring()
+        Symbolic Ring
+        sage: v=symbolic_expression((x,1)); v
+        (x, 1)
+        sage: v.base_ring()               
+        Symbolic Ring
+        sage: v=symbolic_expression((3,1)); v
+        (3, 1)
+        sage: v.base_ring()               
+        Symbolic Ring
+        sage: E = EllipticCurve('15a'); E
+        Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 10*x - 10 over Rational Field
+        sage: v=symbolic_expression([E,E]); v
+        (x*y + y^2 + y == x^3 + x^2 - 10*x - 10, x*y + y^2 + y == x^3 + x^2 - 10*x - 10)
+        sage: v.base_ring()
+        Symbolic Ring
     """
     from sage.symbolic.expression import Expression
     from sage.symbolic.ring import SR
@@ -65,6 +88,8 @@
         return x
     elif hasattr(x, '_symbolic_'):
         return x._symbolic_(SR)
+    elif isinstance(x, (tuple,list)):
+        return vector(SR,x)
     else:
         return SR(x)
 
diff -r 5db30cfa5ba1 -r 40d5603e67a9 sage/calculus/calculus.py
--- a/sage/calculus/calculus.py	Mon May 03 10:53:32 2010 -0700
+++ b/sage/calculus/calculus.py	Mon May 03 22:56:37 2010 -0500
@@ -57,7 +57,7 @@
     sage: g = f.integral(x); g
     -cos(x)/cos(2*y)
 
-Note that these methods require an explicit variable name. If none
+Note that these methods usually require an explicit variable name. If none
 is given, Sage will try to find one for you.
 
 ::
@@ -65,7 +65,43 @@
     sage: f = sin(x); f.derivative()
     cos(x)
 
-However when this is ambiguous, Sage will raise an exception::
+If the expression is a callable symbolic expression (i.e., the
+variable order is specified), then Sage can calculate the matrix
+derivative (i.e., the gradient, Jacobian matrix, etc.) if no variables
+are specified.  In the example below, we use the second derivative
+test to determine that there is a saddle point at (0,-1/2).
+
+::
+
+    sage: f(x,y)=x^2*y+y^2+y
+    sage: f.diff() # gradient
+    ((x, y) |--> 2*x*y, (x, y) |--> x^2 + 2*y + 1)
+    sage: solve(list(f.diff()),[x,y])
+    [[x == -I, y == 0], [x == I, y == 0], [x == 0, y == (-1/2)]]
+    sage: H=f.diff(2); H  # Hessian matrix
+    [(x, y) |--> 2*y (x, y) |--> 2*x]
+    [(x, y) |--> 2*x   (x, y) |--> 2]
+    sage: H(x=0,y=-1/2)
+    [-1  0]
+    [ 0  2]
+    sage: H(x=0,y=-1/2).eigenvalues()
+    [-1, 2]
+
+Here we calculate the Jacobian for the polar coordinate transformation::
+
+    sage: T(r,theta)=[r*cos(theta),r*sin(theta)]
+    sage: T
+    ((r, theta) |--> r*cos(theta), (r, theta) |--> r*sin(theta))
+    sage: T.diff() # Jacobian matrix
+    [   (r, theta) |--> cos(theta) (r, theta) |--> -r*sin(theta)]
+    [   (r, theta) |--> sin(theta)  (r, theta) |--> r*cos(theta)]
+    sage: diff(T) # Jacobian matrix
+    [   (r, theta) |--> cos(theta) (r, theta) |--> -r*sin(theta)]
+    [   (r, theta) |--> sin(theta)  (r, theta) |--> r*cos(theta)]
+    sage: T.diff().det() # Jacobian 
+    (r, theta) |--> r*sin(theta)^2 + r*cos(theta)^2
+   
+When the order of variables is ambiguous, Sage will raise an exception when differentiating::
 
     sage: f = sin(x+y); f.derivative()
     Traceback (most recent call last):
diff -r 5db30cfa5ba1 -r 40d5603e67a9 sage/matrix/matrix0.pyx
--- a/sage/matrix/matrix0.pyx	Mon May 03 10:53:32 2010 -0700
+++ b/sage/matrix/matrix0.pyx	Mon May 03 22:56:37 2010 -0500
@@ -1944,6 +1944,29 @@
             ans.append( sum(tmp) )
         return f(tuple(ans))
 
+    def __call__(self, *args, **kwargs):
+        """
+        Calling a matrix returns the result of calling each component.
+        
+        EXAMPLES::
+        
+            sage: f(x,y) = x^2+y
+            sage: m = matrix([[f,f*f],[f^3,f^4]]); m
+            [    (x, y) |--> x^2 + y (x, y) |--> (x^2 + y)^2]
+            [(x, y) |--> (x^2 + y)^3 (x, y) |--> (x^2 + y)^4]
+            sage: m(1,2)
+            [ 3  9]
+            [27 81]
+            sage: m(y=2,x=1)
+            [ 3  9]
+            [27 81]
+            sage: m(2,1)
+            [  5  25]
+            [125 625]
+        """
+        from constructor import matrix
+        return matrix(self.nrows(), self.ncols(), [e(*args, **kwargs) for e in self.list()])
+
     ###################################################
     # Arithmetic
     ###################################################
diff -r 5db30cfa5ba1 -r 40d5603e67a9 sage/modules/free_module_element.pyx
--- a/sage/modules/free_module_element.pyx	Mon May 03 10:53:32 2010 -0700
+++ b/sage/modules/free_module_element.pyx	Mon May 03 22:56:37 2010 -0500
@@ -1601,9 +1601,28 @@
             (0, 1, 2*x)
             sage: type(v._derivative(x)) == type(v)
             True
+
+        If no variables are specified and the vector contains callable
+        symbolic expressions, then calculate the matrix derivative
+        (i.e., the Jacobian matrix)::
+        
+            sage: T(r,theta)=[r*cos(theta),r*sin(theta)]
+            sage: T
+            ((r, theta) |--> r*cos(theta), (r, theta) |--> r*sin(theta))
+            sage: T.diff() # matrix derivative
+            [   (r, theta) |--> cos(theta) (r, theta) |--> -r*sin(theta)]
+            [   (r, theta) |--> sin(theta)  (r, theta) |--> r*cos(theta)]
+            sage: diff(T) # matrix derivative again
+            [   (r, theta) |--> cos(theta) (r, theta) |--> -r*sin(theta)]
+            [   (r, theta) |--> sin(theta)  (r, theta) |--> r*cos(theta)]
+            sage: T.diff().det() # Jacobian 
+            (r, theta) |--> r*sin(theta)^2 + r*cos(theta)^2
         """
-        if var is None:
-            raise ValueError, "No differentiation variable specified."
+        if var is None: 
+            if sage.symbolic.callable.is_CallableSymbolicExpressionRing(self.base_ring()):
+                return sage.calculus.all.jacobian(self, self.base_ring().arguments())
+            else:
+                raise ValueError, "No differentiation variable specified."
 
         # We would just use apply_map, except that Cython doesn't
         # allow lambda functions
@@ -2041,6 +2060,39 @@
         """
         return vector([e.n(*args, **kwargs) for e in self])
 
+    def function(self, *args):
+        """
+        Returns a vector over a callable symbolic expression ring.
+
+        EXAMPLES::
+
+            sage: x,y=var('x,y')
+            sage: v=vector([x,y,x*sin(y)])
+            sage: w=v.function([x,y]); w
+            ((x, y) |--> x, (x, y) |--> y, (x, y) |--> x*sin(y))
+            sage: w.base_ring()
+            Callable function ring with arguments (x, y)
+            sage: w(1,2)
+            (1, 2, sin(2))
+            sage: w(2,1)
+            (2, 1, 2*sin(1))
+            sage: w(y=1,x=2)
+            (2, 1, 2*sin(1))
+            
+        :: 
+
+            sage: x,y=var('x,y')
+            sage: v=vector([x,y,x*sin(y)])
+            sage: w=v.function([x]); w
+            (x |--> x, x |--> y, x |--> x*sin(y))
+            sage: w.base_ring()    
+            Callable function ring with arguments (x,)
+            sage: w(4)
+            (4, y, 4*sin(y))            
+        """
+        from sage.symbolic.callable import CallableSymbolicExpressionRing
+        return vector(CallableSymbolicExpressionRing(args), self.list())
+
 #############################################
 # Generic sparse element
 #############################################  
diff -r 5db30cfa5ba1 -r 40d5603e67a9 sage/symbolic/expression.pyx
--- a/sage/symbolic/expression.pyx	Mon May 03 10:53:32 2010 -0700
+++ b/sage/symbolic/expression.pyx	Mon May 03 22:56:37 2010 -0500
@@ -2496,6 +2496,13 @@
             sage: SR(1)._derivative()
             0
 
+        If the expression is a callable symbolic expression, and no
+        variables are specified, then calculate the gradient::
+
+            sage: f(x,y)=x^2+y
+            sage: f.diff() # gradient
+            ((x, y) |--> 2*x, (x, y) |--> 1)
+            
         TESTS:
 
         Raise error if no variable is specified and there are multiple
@@ -2525,6 +2532,8 @@
                 symb = vars[0]
             elif len(vars) == 0:
                 return self._parent(0)
+            elif sage.symbolic.callable.is_CallableSymbolicExpression(self):
+                return self.gradient()
             else:
                 raise ValueError, "No differentiation variable specified."
         if not isinstance(deg, (int, long, sage.rings.integer.Integer)) \
