SymPy - произвольное количество символов - PullRequest
21 голосов
/ 29 февраля 2012

Я кодирую функцию, которая решает произвольное число одновременных уравнений. Количество уравнений задается одним из параметров функции, и каждое уравнение строится из числа символов - столько же символов, сколько существует уравнений. Это означает, что я не могу просто жестко закодировать уравнения или даже символы, необходимые для составления уравнений; функция должна иметь возможность обрабатывать любое количество уравнений. Итак, мой вопрос, как мне составить список символов?

У меня есть одно возможное решение, но моя интуиция говорит мне, что оно не будет очень эффективным. Пожалуйста, дайте мне знать, если есть лучший способ сделать это.

Я новичок в 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...

Это лучший способ сделать это, или есть более эффективный подход?

Ответы [ 7 ]

33 голосов
/ 29 февраля 2012

Функцию 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₁₄)
7 голосов
/ 27 октября 2012

numbered_symbols("t") вернет генератор, который генерирует t0, t1, t2 и т. Д. Вы можете использовать параметр start, чтобы выбрать другое начальное значение.И если вы хотите использовать фиктивные переменные, используйте numbered_symbols("t", cls=Dummy).

2 голосов
/ 16 апреля 2019

Не знаю, добавлю ли еще какую-нибудь полезную информацию в тему, но я использую следующий метод для создания списка символических переменных:

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
2 голосов
/ 16 июля 2017

Используя 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
2 голосов
/ 29 февраля 2012

Вы можете сделать подкласс 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]
2 голосов
/ 29 февраля 2012

Ваш подход хорош, хотя нет необходимости хранить имена символов отдельно (вы можете получить доступ к имени символа через его свойство name).

Кроме того, вы можете выразить создание символа немного более кратко (хотя и не более эффективно), например:

symbolList = map(lambda i: Symbol('t' + str(i)), xrange(numEquations))

Однако для вашего случая использования (временные переменные) фиктивные переменныеВероятно, путь таков:

symbolList = map(Dummy, xrange(numEquations))

Это на самом деле не более эффективно, поскольку внутри класса Dummy также используется счетчик для генерации уникальных имен, но он немного чище и яснее.

0 голосов
/ 10 мая 2019

Мне нравится подход @ 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

BTW, 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
...