sympy: объект 'Transpose' не имеет атрибута tolist

Я пытаюсь сделать некоторые символические матричные вычисления с sympy. Моя цель-получить символическое представление результата матричных вычислений. Я столкнулся с некоторыми проблемами, которые я свел к этому простому примеру, в котором я пытаюсь оценить результат возведения в степень указанной матрицы и умножения ее на произвольный вектор.

>>> import sympy
>>> v = sympy.MatrixSymbol('v', 2, 1)
>>> Z = sympy.zeros(2, 2)  # create 2x2 zero matrix
>>> I = sympy.exp(Z)  # exponentiate zero matrix to get identity matrix
>>> I * v
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "sympy/matrices/matrices.py", line 507, in __mul__
    blst = B.T.tolist()
AttributeError: 'Transpose' object has no attribute 'tolist'

напротив, если я непосредственно создаю матрицу идентичности, а затем умножаю ее на v, то нет проблема:

>>> I_ = sympy.eye(2)  # directly create the identity matrix
>>> I_ == I  # check the two matrices are equal
True
>>> I_ * v
v

одна вещь, которую я отметил, заключается в том, что две матрицы идентичности имеют разные классы:

>>> I.__class__
sympy.matrices.immutable.ImmutableMatrix
>>> I_.__class__
sympy.matrices.dense.MutableDenseMatrix

Я также обнаружил, что вызов as_mutable() метод обойти.

>>> I.as_mutable() * v
v

всегда ли надо ставить as_mutable() вызовы на протяжении всех вычислений линейной алгебры? Я предполагаю, что нет, и что вместо этого эти ошибки предполагают, что я использую неправильную стратегию для решения своей проблемы, но я не могу понять, какая правильная стратегия должен быть. У кого-нибудь есть указания?

Я прочитал страницу документации на Неизменяемые Матриц но я все равно мог бы помочь понять, как важны их различия со стандартными изменяемыми матрицами и почему некоторые операции (например, sympy.exp) преобразование между этими различными классами.

1 ответов


я бы сказал, что это ошибка в Sympy:

в Python, вы можете перегрузка оператора умножения с обеих сторон. A*B может внутренне обрабатываться либо вызовом A.__mul__(B) или B.__rmul__(A). Первые вызовы Python A.__mul__, а если этот метод не существует или возвращает NotImplemented, затем Python пытается B.__rmul__ автоматически. SymPy вместо этого использует декоратора под названием call_highest_priority чтобы решить, какую из обеих реализаций использовать. Это выглядит вверх _op_priority соответствующих классов и вызывает функцию реализации с более высоким приоритетом. Приоритеты в вашем случае 11 для v и I и 10.01 на I_, так что I предпочтительнее. Кроме того, базовая реализация __mul__, который I использует, не хватает декоратор.

короче, I*v в конечном итоге всегда звонит I.__mul__ и __mul__ не может обрабатывать MatrixSymbols, но не возвращается NotImplemented либо. v.__rmul__(I) работает ожидаемый.

правильным решением было бы захватить AttributeError на matrices.py и возврат NotImplemented, то есть

try:
    blst = B.T.tolist()
except AttributeError:
    return NotImplemented

Python автоматически вернется к __rmul__. Hack'ish исправить было бы настроить _op_priority. В любом случае, вы должны подать отчет об ошибке: если ошибка была по дизайну (то есть, если вы случайно попробовали что-то, что не должно работать), то сообщение об ошибке скажет так.