SymPy - произвольное количество символов
Я кодирую функцию, которая решает произвольное число одновременных уравнений. Количество уравнений задается одним из параметров функции, и каждое уравнение построено из числа символов - столько символов, сколько есть уравнений. Это означает, что я не могу просто закодировать уравнения или даже символы, необходимые для объединения уравнений; функция должна иметь возможность обрабатывать любое количество уравнений. Итак, мой вопрос: как мне создать список символов?
У меня есть одно возможное решение, но мой кишок говорит мне, что он не будет очень эффективным. Пожалуйста, дайте мне знать, если есть лучший способ сделать это.
Я новичок в SymPy, и я все еще чувствую свой путь. Насколько я вижу, символы должны быть определены строкой. Поэтому я могу создать ряд строк, добавив добавочное число к букве (например, "t0", "t1" и т.д.), Добавьте их в список и затем создайте символы, используя эти строки в качестве параметров. Эти символы сами будут храниться в списке и будут использоваться для создания уравнений.
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...
Это лучший способ сделать это, или есть более эффективный подход?
Ответы
Ответ 1
Функция 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₁₄)
Ответ 2
numbered_symbols("t")
возвращает генератор, который генерирует t0
, t1
, t2
и т.д. Вы можете использовать параметр start
, чтобы выбрать другое начальное значение. И если вы хотите использовать фиктивные переменные, используйте numbered_symbols("t", cls=Dummy)
.
Ответ 3
Вы можете создать подкласс dict
, который автоматически возвращает 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]
Ответ 4
С locals()
и пониманием слова вы можете итеративно генерировать оба символа и локальные переменные python с похожим именем. Например:
>>> symbols_dict = dict(('a%d'%k, symbols('a%d'%k)) for k in range(3))
>>> locals().update(symbols_dict)
Проверка работы:
>>> print(expand((a0+a2)*(a0+a1**2)))
a0**2 + a0*a1**2 + a0*a2 + a1**2*a2
Ответ 5
Ваш подход прекрасен, хотя нет необходимости хранить имена символов отдельно (вы можете получить доступ к имени символа через его свойство name
).
Кроме того, вы можете выразить создание символа немного более сжато (хотя и не более эффективно), например:
symbolList = map(lambda i: Symbol('t' + str(i)), xrange(numEquations))
Однако для вашего варианта использования (временные переменные) необязательными являются следующие переменные:
symbolList = map(Dummy, xrange(numEquations))
Это не более эффективно, так как внутри класса Dummy
также используется счетчик для генерации уникальных имен, но он немного чище и понятнее.
Ответ 6
Не знаю, добавлю ли еще какую-нибудь полезную информацию в тему, но я использую следующий метод для создания списка символических переменных:
x = [sympy.symbols('x%d' % i) for i in range(3)]
И тогда я могу использовать это нормально в уравнении:
eq = x[0]**2 + x[1]*2 + x[2]
print(sympy.diff(eq,x[0]))
>>> 2*x0
Ответ 7
Мне нравится подход @jp-sena, и то, что я собираюсь предложить, выглядит очень похоже на него. Разница в том, что вам не нужно знать, сколько символов вам понадобится - вы просто получите доступ к нужному количеству по индексу. Используйте IndexedBase
качестве вашего символа:
>>> 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]
Для целей отображения вы можете создать словарь замены. Для создания нумерованных символов вы можете сделать
>>> 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
Или, если вы используете менее 26 символов, вы можете использовать буквы с
>>> 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
Кстати, x
- это IndexedBase, а x[1]
- индексированный объект, у которого .base
равен x
а чьи .indices
- это кортеж из любых чисел, указанных в скобках. И IndexedBase, и Indexed будут отображаться в запросе .free_symbols
.
>>> (x[1,2] + 3).free_symbols
{x, x[1, 2]}
>>> x[1, 2].indices
(1, 2)
>>> x[1].base
x