Differentiation using a vector of variables

345 views
Skip to first unread message

Saullo Castro

unread,
Oct 31, 2013, 6:09:53 AM10/31/13
to sy...@googlegroups.com
I have the functional:


Where A is a function of "v". The non-linear system of equations necessary to find "v" is obtained doing:

According to the differentiation rules, this system could be written in matrix form as:

So I've implemented in Sympy, with the help of NumPy "ndarray" the differentiation about a vector. In this case the shape of (\partial A / \partial v is (n X n X n), where "n" is the length of vector "v".

The function is simple:

def vdiff(x, vector):
    x
= np.array(x)
    shape
= x.shape
    ans
= [np.array([e.diff(vi) for e in x.ravel()]) for vi in vector]
    ans
= [a.reshape(shape) for a in ans]
   
return np.array(ans).swapaxes(0, 1)

 

And I've tested with two different cases:


def test_00():
   
from sympy.abc import a, b, c, x
    A11
= x*a*c**2
    A12
= x**2*a*b*c
    A13
= x**2*a**3*b**5
    A21
= x**3*a**2*b*c
    A22
= x**4*a*b**2*c**5
    A23
= 5*x**4*a*b**2*c
    A31
= x**4*a*b**2*c**4
    A32
= 4*x**4*a*b**2*c**2
    A33
= 4*x**4*a**5*b**2*c
    A
= np.array([[A11, A12, A13],
                 
[A21, A22, A23],
                 
[A31, A32, A33]])
    v
= np.array([a, b, c])
    F
= (v.T.dot(A)).dot(v)
   
Av = vdiff(A, v)
    p1
= v.dot(A)
    p2
= A.dot(v)
    p3
= v.dot(Av.dot(v))
   
new = p1 + p2 + p3
   
ref = np.array([F.diff(a), F.diff(b), F.diff(c)])
   
print sympy.simplify(Matrix(ref-new))

def test_01():
   
from sympy.abc import a, b, c, x
    sympy
.var('c1, c2')
    A11
= x*a*c**2
    A12
= x**2*a*b*c
    A13
= x**2*a**3*b**5
    A21
= x**3*a**2*b*c
    A22
= x**4*a*b**2*c**5
    A23
= 5*x**4*a*b**2*c
    A
= np.array([[A11, A12, A13],
                 
[A21, A22, A23]])
    v
= np.array([a, b, c])
    cc
= np.array([c1, c2])
    F
= cc.dot(A.dot(v))
   
ref = np.array([F.diff(a), F.diff(b), F.diff(c)])
   
Av = vdiff(A, v)
    p1
= cc.dot(A)
    p2
= cc.dot(Av.dot(v))
   
new = p1 + p2
   
print sympy.simplify(Matrix(ref-new))


I'd like to share here and get some feedback in case someone has a more straightforward way to implement this...


Thank you!

Saullo





Aaron Meurer

unread,
Oct 31, 2013, 3:52:45 PM10/31/13
to sy...@googlegroups.com
Ideally, we would implement these rules symbolically, so that they work even for something like MatrixSymbol('x', n, n). See https://code.google.com/p/sympy/issues/detail?id=2759. Getting this working would be a really nice feature for SymPy.

Aaron Meurer


--
You received this message because you are subscribed to the Google Groups "sympy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sympy+un...@googlegroups.com.
To post to this group, send email to sy...@googlegroups.com.
Visit this group at http://groups.google.com/group/sympy.
For more options, visit https://groups.google.com/groups/opt_out.

F. B.

unread,
Nov 1, 2013, 7:34:59 AM11/1/13
to sy...@googlegroups.com
By the way, as far as you work on 1D and 2D arrays, you don't need numpy, sympy can already handle those things. Greater dimensions are not yet supported in sympy, unless you use tensor products in the diffgeom module, but the representation of n-dim arrays is very strange there. As pointed out by Aaron in a PR, you don't get a real advantage on dtype=object in numpy over a possible pure python implementation.

Indexed derivatives are an urgent need for modern physics, otherwise it is really hard to transcribe formulae to a CAS. We need them in the tensor module.

There is already some stuff in the diffgeom module, which provides differential and covariant derivatives for its field objects. I think it only works within the diffgeom module.

Concerning derivatives by a vector, the diffgeom module handles them in a clean way. I mean, you define a manifold, then a patch on the manifold, and finally a coordinate system on the patch. The coordinate system specifies the basis symbols, which you can use on scalar, vector, and tensor fields defined on that patch. As an example:

>>> from sympy import Function
>>> from sympy.diffgeom.rn import R2
>>> from sympy.diffgeom import Differential
>>> from sympy import pprint
>>> g = Function('g')
>>> s_field = R2.x**2 * R2.y
>>> e_x, e_y, = R2.e_x, R2.e_y

>>> dg = Differential(s_field)

>>> pprint(dg(e_x))
2*x*y
>>> pprint(dg(e_y))
2
x

That is, the diffgeom already handles a far more general case. It would be nice to have the diffgeom module interact with other parts of sympy, rather than implementing everything separately.

By the way, there is a problem associated with derivatives by a vector: how do you handle non-single-symbol expression in the derivative? I.e., if v = [a, b, a**2 + sin(b)], how do you handle a derivation of a matrix by v? In the diffgeom module you define the coordinate system, the coordinate symbols are instances of BaseScalarField, not generic expressions.

In any case, indexed derivations are a special case of the more general tools already implemented in diffgeom, I mean, by your method you are assuming:
  1. a flat space.
  2. a single patch on the flat space.
  3. an ill-defined coordinate system, (you put it every time inside the derivation).
  4. Euclidean metric (i.e. no difference between covariant and contravariant components of the objects to be derived).

I think that what is really worth, is to make diffgeom interact with matrices and vectors, and maybe simplify its usage when the 4 points here above are verified.

Saullo Castro

unread,
Nov 1, 2013, 6:15:03 PM11/1/13
to sy...@googlegroups.com
Well, derivating by a vector containing Symbols is fine, but I am not familiar with the application cases where the derivative is performed using a vector containing expressions...


2013/11/1 F. B. <franz....@gmail.com>

--
You received this message because you are subscribed to a topic in the Google Groups "sympy" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/sympy/P8Q3G5bHe-U/unsubscribe.
To unsubscribe from this group and all its topics, send an email to sympy+un...@googlegroups.com.

Alan Bromborsky

unread,
Nov 1, 2013, 7:23:00 PM11/1/13
to sy...@googlegroups.com
Consider Lagrangian field theory where the derivatives are taken with respect to the gradient of a field.  In the case of quantum electrodynamics with respect to the gradient of a spinor field.

F. B.

unread,
Nov 2, 2013, 6:07:25 AM11/2/13
to sy...@googlegroups.com


On Saturday, November 2, 2013 12:23:00 AM UTC+1, brombo wrote:
Consider Lagrangian field theory where the derivatives are taken with respect to the gradient of a field.  In the case of quantum electrodynamics with respect to the gradient of a spinor field.

Yes, that would be needed. I am wondering, is there a generic algorithm for functional derivatives, or is it more likely to be a complicated matter?

Saullo Castro

unread,
Nov 2, 2013, 6:46:27 AM11/2/13
to sy...@googlegroups.com
I believe we can make a variable transform and then apply the derivative using the expression converted to a variable, like:

    x = a**2 + c + d**3
    x.diff((a + c**2))

changing variables:

    v = a + c**2
    a = v - c**2
    c = (v-a)**0.5

the new x will be:

    x2 = (v-c**2)**2 + (v-a)**0.5 + d**3

and the derivative could be computed as:

    x2.diff(v)

is that reasonable?


2013/11/2 F. B. <franz....@gmail.com>


On Saturday, November 2, 2013 12:23:00 AM UTC+1, brombo wrote:
Consider Lagrangian field theory where the derivatives are taken with respect to the gradient of a field.  In the case of quantum electrodynamics with respect to the gradient of a spinor field.

Yes, that would be needed. I am wondering, is there a generic algorithm for functional derivatives, or is it more likely to be a complicated matter?

--

Saullo Castro

unread,
Nov 2, 2013, 6:48:04 AM11/2/13
to sy...@googlegroups.com
just adding... after `x2.diff(v)` the `v` must be replaced by `a + c**2` again...



2013/11/2 Saullo Castro <saullo...@gmail.com>

F. B.

unread,
Nov 2, 2013, 8:24:53 AM11/2/13
to sy...@googlegroups.com


On Saturday, November 2, 2013 11:46:27 AM UTC+1, Saullo Castro wrote:
I believe we can make a variable transform and then apply the derivative using the expression converted to a variable, like:

    x = a**2 + c + d**3
    x.diff((a + c**2))

changing variables:

    v = a + c**2
    a = v - c**2
    c = (v-a)**0.5

the new x will be:

    x2 = (v-c**2)**2 + (v-a)**0.5 + d**3

and the derivative could be computed as:

    x2.diff(v)

is that reasonable?

Yes, it is.

Are you going to use .subs( ) or solve( ) ?

Saullo Castro

unread,
Nov 2, 2013, 10:14:14 AM11/2/13
to sy...@googlegroups.com
To transform the variables "solve" and to do the back-substitution "subs"...



2013/11/2 F. B. <franz....@gmail.com>

--

Aaron Meurer

unread,
Nov 2, 2013, 12:48:30 PM11/2/13
to sy...@googlegroups.com
But in general, you can't invert formulas (and even if you
mathematically can, it doesn't mean that solve() can do it).

Aaron Meurer
> You received this message because you are subscribed to the Google Groups
> "sympy" group.
> To unsubscribe from this group and stop receiving emails from it, send an

F. B.

unread,
Nov 2, 2013, 4:16:39 PM11/2/13
to sy...@googlegroups.com


On Saturday, November 2, 2013 5:48:30 PM UTC+1, Aaron Meurer wrote:
But in general, you can't invert formulas (and even if you
mathematically can, it doesn't mean that solve() can do it).


I was just thinking about this, and about the more general case where you are deriving by unknown expression.

I suggest that in such cases the differentiation returns an unevaluated derivative.

It would be nice to handle derivation by another function, for example:

>>> x.diff(f(x))
Derivative(x, f(x))
>>> x.diff(f(y))
Derivative(x, f(y))
>>> f(x).diff(g(x))
Derivative(f(x), g(x))
>>> f(x).diff(g(y))
Derivative(f(x), g(y))

At least, I would start be leaving the derivative unevaluated, so in the future it will be easier to add tools to handle functional derivatives.

Saullo, do you think you can add something like this?
 

Aaron Meurer

unread,
Nov 2, 2013, 8:07:03 PM11/2/13
to sy...@googlegroups.com
Wait, why is x.diff(f(x)) not 0? We discussed this quite at length
when we first implemented the ability to do this (you can probably
find the discussion on the mailing list if you search for it), and we
came to the conclusion that dF(x, f(x))/df(x) as used in variational
calculus means nothing more than dF(x, y)/dy|y=f(x). On other words,
the fact that f(x) depends on x is irrelevant. You are just taking the
derivative with respect to the second "variable" in the expression,
which happens to be evaluated at f(x). See also the docstring of
Derivative.

Aaron Meurer

Saullo Castro

unread,
Nov 3, 2013, 4:16:21 PM11/3/13
to sy...@googlegroups.com
This is the new prototype of vdiff, but it still cannot unleash the Derivative object unevaluated:

def vdiff(x, vector):
    x = np.array(x)
    shape = x.shape
    ans = []
    for vi in vector:
        if vi.is_Symbol:
            tmp = []
            for e in x.ravel():
                tmp.append(e.diff(vi))
        else:
            subs = {}
            new_var = sympy.var('new_var')
            for s in vi.free_symbols:
                subs[s] = solve(new_var - vi, s)[0]
            tmp = []
            for e in x.ravel():
                e = e.subs(subs)
                e = e.diff(new_var)
                e = e.subs({new_var: vi})
                tmp.append(e.diff(new_var))
        ans.append(np.array(tmp))
    ans = [a.reshape(shape) for a in ans]
    return np.array(ans).swapaxes(0, 1)

Chris Smith

unread,
Nov 25, 2013, 11:25:04 AM11/25/13
to sy...@googlegroups.com
In the code you last posted, you do a substitution of new_var with vi and then differentiate wrt new_var. This will necessarily give you 0, won't it?  Is this what you are trying to do:

>>> def vdiff(x, vector):
...     ans = []
...     for vi in vector:
...         if vi.is_Symbol:
...             tmp = []
...             for e in x:
...                 tmp.append(e.diff(vi))
...         else:
...             subs = {}
...             new_var = Dummy()
...             for s in vi.free_symbols:
...                 subs[s] = solve(new_var - vi, s)[0]
...             tmp = []
...             for e in x:
...                 e = e.subs(subs, simultaneous=True)
...                 d = Dummy('ei')
...                 e = idiff(d-e, d, new_var)
...                 e = e.subs({new_var: vi})
...                 tmp.append(e)
...         ans.append(tmp)
...     return ans
...
>>> vdiff([x, x+y], [x, x-c])
[[1, 1], [1, 1]]
>>> vdiff([x, x+y], [x, exp(x)-c])
[[1, 1], [exp(-x), exp(-x)]]
>>> vdiff([x, x+y], [x, exp(x)-y])
[[1, 1], [exp(-x), (-exp(x) + 1)*exp(-x)]]

Saullo Castro

unread,
Dec 3, 2013, 7:26:22 AM12/3/13
to sy...@googlegroups.com
sorry by the late reply... I still cannot take the time to answer this question.... but I will do it soon



2013/11/25 Chris Smith <smi...@gmail.com>

--
You received this message because you are subscribed to a topic in the Google Groups "sympy" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/sympy/P8Q3G5bHe-U/unsubscribe.
To unsubscribe from this group and all its topics, send an email to sympy+un...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages