1

Here's what I'm doing in a SymPy session:

from sympy import *
xi1,xi2,xi3 = symbols('xi_1,xi_2,xi_3')
N1 = 1-xi1-xi2-xi3
N2 = xi3
N3 = xi1
N4 = xi2
x1,x2,x3,x4 = symbols('x_1, x_2, x_3, x_4')
x = N1*x1+N2*x2+N3*x3+N2*x4
subdict = {x1:Matrix([0.025,1.0,0.0]), x2 : Matrix([0,1,0]), x3:Matrix([0, 0.975, 0]), x4:Matrix([0,0.975,0.025])}
x.subs(subdict)
test.subs({xi1:1, xi2:0,xi3:0})

To me we are simply multiplying some scalars with some vectors then adding them up. However SymPy would disagree and throws a ginormous error for which the last line is:

TypeError: cannot add <class 'sympy.matrices.immutable.ImmutableDenseMatrix'> and <class 'sympy.core.numbers.Zero'>

Why is this a problem? Is there a workaround for what I am trying to do?

halfer
  • 19,824
  • 17
  • 99
  • 186
user32882
  • 5,094
  • 5
  • 43
  • 82

1 Answers1

2

I suspect that what is happening is that before the matrix is substituted you substitute a 0 which makes 0*matrix_symbol = 0 instead of a matrix of zeros. Terms that end up being matrices cannot be added to 0 and thus the error. My attempts at using the simultaneous flag or xreplace instead of subs give the same result (on sympy.live.org). Then I tried to do the substitutions in reversed order, passing them as a list with the matrices first. Still didn't work. It looks like subs assumes that 0*foo is 0. An issue at sympy issues should be raised if there is not already an existing issue.

The workaround is to do the scalar substitutions first, allowing the zero terms to disappear. Then do a subs with the matrices. So this will require 2 calls to subs.

A true, hackish workaround for doing substitution with 0 is this:

def remul(m):
  rv = 1
  for i in m.args:
    rv *= i
  return rv

expr = x*y
mat = expr.subs(x, randMatrix(2)) # replace x with matrix
expr = mat.replace( # replace y with scalar 0
    lambda m: m.is_Mul,
    lambda m: remul(Mul(*[i.subs(y, 0) for i in m.args], evaluate=False)))
smichr
  • 16,948
  • 2
  • 27
  • 34
  • The issue doesn't seem to be restricted to 0... here is a minimal example that throws the same error the OP described in SymPy 1.1.1: `x,y=symbols('x y')` then `(x+y).subs({x: Matrix([1,2]), y: Matrix([3,4])})` –  Sep 07 '17 at 23:35
  • I get a different error on sympy.live.org but will investigate with the current version and report back. Thanks for the heads up. – smichr Sep 07 '17 at 23:42
  • 1
    The errors are both related to problems in the flattening routines for Mul (@32882 's issue) and Add (@Michelle 's). I have opened a PR that fixes these issues. The substitution is still order dependent, however, so if (after the fix) you want to keep the result as a matrix, you will need to use `simultaneous=True`. See https://github.com/sympy/sympy/pull/13279 – smichr Sep 08 '17 at 16:58
  • So for a non-sympy developer do we have a simple resolution to this problem? This is a straightforward case of scalar times vector.... – user32882 Sep 15 '17 at 09:15
  • Have you downloaded the most recent version of SymPy and given this a try? – smichr Sep 16 '17 at 03:58