9

I am using sympy from time to time, but am not very good at it. At the moment I am stuck with defining a list of indexed variables, i.e. n1 to nmax and performing a summation on it. Then I want to be able to take the derivative:

So far I tried the following:

numSpecies = 10
n = IndexedBase('n')
i = symbols("i",cls=Idx)
nges = summation(n[i],[i,1,numSpecies])

However, if i try to take the derivative with respect to one variable, this fails:

diff(nges,n[5])

I also tried to avoid working with IndexedBase.

numSpecies = 10
n = symbols('n0:%d'%numSpecies)
k = symbols('k',integer=True)
ntot = summation(n[k],[k,0,numSpecies])

However, here already the summation fails because mixing python tuples and the sympy summation.

How I can perform indexedbase derivatives or some kind of workaround?

user
  • 5,370
  • 8
  • 47
  • 75
Johannes
  • 161
  • 1
  • 6
  • 1
    Thanks to Bill Bell and Stelios for the answers to my specific problem. I made my example as simple as possible, therefore it might seem real trivial. In the long run I need to define summations of more complicated equations. My problem is in the area of chemical engineering. Often you encounter equations where you have a sum of some kind of property weighted with the respected mole fraction of a chemical species. Often it is necessary to calculate the derivative of said function with respect to the change of a specific species. – Johannes Aug 28 '16 at 17:47
  • @Johannes You are welcome! I believe you should now be able to handle more complicated problems like weighted sums. If you are still having problems, do not hesitate to post another question. – Stelios Aug 28 '16 at 18:13

3 Answers3

5

With SymPy's development version, your example works.

To install SymPy's development version, just pull it down with git:

git clone git://github.com/sympy/sympy.git
cd sympy

Then run python from that path or set the PYTHONPATH to include that directory before Python's default installation.

Your example on the development version:

In [3]: numSpecies = 10

In [4]: n = IndexedBase('n')

In [5]: i = symbols("i",cls=Idx)

In [6]: nges = summation(n[i],[i,1,numSpecies])

In [7]: nges
Out[7]: n[10] + n[1] + n[2] + n[3] + n[4] + n[5] + n[6] + n[7] + n[8] + n[9]

In [8]: diff(nges,n[5])
Out[8]: 1

You could also use the contracted form of summation:

In [9]: nges_uneval = Sum(n[i], [i,1,numSpecies])

In [10]: nges_uneval
Out[10]: 
  10      
 ___      
 ╲        
  ╲   n[i]
  ╱       
 ╱        
 ‾‾‾      
i = 1     

In [11]: diff(nges_uneval, n[5])
Out[11]: 
  10      
 ___      
 ╲        
  ╲   δ   
  ╱    5,i
 ╱        
 ‾‾‾      
i = 1     

In [12]: diff(nges_uneval, n[5]).doit()
Out[12]: 1

Also notice that in the next SymPy version you will be able to derive symbols with symbolic indices:

In [13]: j = symbols("j")

In [13]: diff(n[i], n[j])
Out[13]: 
δ   
 j,i

Where you get the Kronecker delta.

If you don't feel like installing the SymPy development version, just wait for the next full version (probably coming out this autumn), it will support derivatives of IndexedBase.

Francesco Bonazzi
  • 1,917
  • 9
  • 10
  • One quick question though. Do you know if it possible to define a indexed base function, i. e. f_i(T) with i being the index? So far I could not find anything in the documentation. Not a must have, but with this functionality I could write down my whole problem and tackle it with sympy in a sound way. Best regards. – Johannes Aug 29 '16 at 17:53
  • I don't think that's currently supported. IndexedBase requires a symbol or a string as its argument. You may still try subclassing IndexedBase and override its methods, but that's a bit long. – Francesco Bonazzi Aug 30 '16 at 08:09
1

I don't know why the IndexedBase approach does not work (I would be interested to know also). You can, however, do the following:

import sympy as sp

numSpecies = 10
n = sp.symbols('n0:%d'%numSpecies)   # note that n equals the tuple (n0, n1, ..., n9)

ntot = sum(n)       # sum elements of n using the standard
                    # Python function for summing tuple elements
#ntot = sp.Add(*n)  # same result using Sympy function

sp.diff(ntot, n[5])
Stelios
  • 5,271
  • 1
  • 18
  • 32
1

I'm not clear about what you want to do. However, perhaps this will help. Edited in response to two comments received.

from sympy import *

nspecies = 10
[var('n%s'%_) for _ in range(nspecies)]

expr = sympify('+'.join(['n%s'%_ for _ in range(nspecies)]))
expr
print ( diff(expr,n1) )

expr = sympify('n0**n1+n1**n2')
expr
print ( diff(expr,n1) )

Only the first expression responds to the original question. This is the output.

1
n0**n1*log(n0) + n1**n2*n2/n1
Bill Bell
  • 21,021
  • 5
  • 43
  • 58