I am coding a function that solves an arbitrary number of simultaneous equations. The number of equations is set by one of the parameters of the function and each equation is built from a number of symbols - as many symbols as there are equations. This means that I can't simply hardcode the equations, or even the symbols needed to put together the equations; the function needs to be able to handle any number of equations. So, my question is, how do I produce a list of symbols?
I have one possible solution, but my gut tells me that it's not going to be very efficient. Please let me know if there is a better way of doing this.
I'm new to SymPy and am still feeling my way about. As far as I can see, Symbols need to be defined with a string. Therefore, I can produce a series strings via appending an incrementing number to a letter (say 't0', 't1', etc), add them to a list and then create the symbols using those strings as parameters. Those symbols would themselves be stored in a list and would be used to produce the equations.
def solveEquations(numEquations):
symbolNameList = []
symbolList = []
equationList = []
for i in range(numEquations):
name = 't' + str(i)
symbolNameList.append(name)
symbolList.append(Symbol(name))
for i in range(numEquations):
equation = 0
for sym in symbolList:
equation += sym ** i # Or whatever structure the equation needs
equationList.append(equation)
#Then go on to solve the equations...
Is this the best way of doing this, or is there a more efficient approach?
The symbols
function can be used to easily generate lists of symbols
In [1]: symbols('a0:3')
Out[1]: (a₀, a₁, a₂)
In [2]: numEquations = 15
In [3]: symbols('a0:%d'%numEquations)
Out[3]: (a₀, a₁, a₂, a₃, a₄, a₅, a₆, a₇, a₈, a₉, a₁₀, a₁₁, a₁₂, a₁₃, a₁₄)
numbered_symbols("t")
will return a generator that generates t0
, t1
, t2
, etc. You can use the start
parameter to choose a different starting value. And if you want to use dummy variables, use numbered_symbols("t", cls=Dummy)
.
With locals()
and dictionary comprehension, you could iteratively generate both symbols and python local variables with a similar name. For example:
>>> symbols_dict = dict(('a%d'%k, symbols('a%d'%k)) for k in range(3))
>>> locals().update(symbols_dict)
Checking that it works:
>>> print(expand((a0+a2)*(a0+a1**2)))
a0**2 + a0*a1**2 + a0*a2 + a1**2*a2
Your approach is fine, though there's no need to store the symbol names separately (you can access a symbol's name via its name
property).
Also, you could express the symbol creation a little more concisely (though no more efficiently), e.g.:
symbolList = map(lambda i: Symbol('t' + str(i)), xrange(numEquations))
However, for your use case (temporary variables), dummy variables are probably the way to go:
symbolList = map(Dummy, xrange(numEquations))
This isn't really any more efficient, since internally the Dummy
class is also using a counter to generate unique names, but it's a bit cleaner and clearer.
You could make a subclass of dict
which automatically returns Symbols
:
import sympy as sym
class SymDict(dict):
# http://stackoverflow.com/a/3405143/190597
def __missing__(self, key):
self[key]=sym.Symbol(key)
return self[key]
def solveEquations(numEquations):
symbol = SymDict()
symbolList = ['t'+str(i) for i in range(numEquations)]
equationList = [sum(symbol[s]**i for s in symbolList)
for i in range(numEquations)]
print(equationList)
solveEquations(3)
# [3, t0 + t1 + t2, t0**2 + t1**2 + t2**2]
Don't know if add any more useful information to the topic, but I use the following method to create a list of symbolic variables:
x = [sympy.symbols('x%d' % i) for i in range(3)]
And then I can use it normally in an equation:
eq = x[0]**2 + x[1]*2 + x[2]
print(sympy.diff(eq,x[0]))
>>> 2*x0
I like the approach given by @j-p-sena and what I am going to suggest looks a lot like it. The difference is that you don't have to know how many symbols you are going to need -- you will just have access to as many as you need by index. Use the IndexedBase
as your symbol:
>>> x = IndexedBase('x') # you've got access to a virtual array of x values
>>> solve(x[1]**2 + 1/x[4], x[4])
[-1/x[1]**2]
For display purposes you might want to create a replacement dictionary. To create numbered symbols you could do
>>> reps = dict(zip([x[i] for i in range(n_used+1)], numbered_symbols('c')))
>>> (x[2]**2 + 1/x[4]).subs(reps)
c2**2 + 1/c4
Or, if you are using less than 26 symbols you could use letters with
>>> reps = dict(zip([x[i] for i in range(n_used+1)], symbols('a:z')))
>>> (x[2]**2 + 1/x[4]).subs(reps)
c**2 + 1/e
BTW, x
is an IndexedBase and x[1]
is an Indexed object whose .base
is x
and whose .indices
are a tuple of whatever numbers appear in the brackets. Both the IndexedBase and Indexed will show up in a .free_symbols
query.
>>> (x[1,2] + 3).free_symbols
{x, x[1, 2]}
>>> x[1, 2].indices
(1, 2)
>>> x[1].base
x
来源:https://stackoverflow.com/questions/9492944/sympy-arbitrary-number-of-symbols