Repository: sympy/sympy
Pull request: solved Incorrect lambdify of constant times matrix symbol
<!-- Your title above should be a short description of what
was changed. Do not include the issue number in the title. -->

#### References to other Issues or PRs
<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact
format, e.g. "Fixes #1234". See
https://github.com/blog/1506-closing-issues-via-pull-requests . Please also
write a comment on that issue linking back to this pull request once it is
open. -->
Fixes #15827 

#### Brief description of what is fixed or changed
(integer.dot(numpymatrix)) is not define but (numpymatrix).dot(intger) define so i just change the order of dot product.
Now in master-
```
A = MatrixSymbol("A", 3, 3)
 f = lambdify(A, 2*A) 
```
So it it taking as `(2).dot(A)` and raising error (number has no dot product).
So i change the order of scalar multiplication now it is working like
```
A = MatrixSymbol("A", 3, 3)
 f = lambdify(A, 2*A) 
```
`(A).dot(2).`
and it is scalar multiplication with matrix so no commutative property require.


#### Other comments
example 
```
A = MatrixSymbol("A", 3, 3)
k=Symbol("k",3,3)
 f = lambdify(A, (2+k)*A) or f = lambdify(A, (2*k)*A)
```
this type is also not working.

#### Release Notes

<!-- Write the release notes for this release below. See
https://github.com/sympy/sympy/wiki/Writing-Release-Notes for more information
on how to write release notes. The bot will check your release notes
automatically to see if they are formatted correctly. -->

<!-- BEGIN RELEASE NOTES -->
-  printing
    - change numpy matmul function. This fixes things like `lambdify(A, 2*A)` where `A` is a `MatrixSymbol`.
<!-- END RELEASE NOTES -->


Problem statement:
Incorrect lambdify of constant times matrix symbol
```
>>> A = MatrixSymbol("A", 3, 3)
>>> f = lambdify(A, 2*A)
>>> import numpy as np
>>> f(np.array([[1, 2, 3], [1, 2, 3], [1, 2, 3]]))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<lambdifygenerated-4>", line 2, in _lambdifygenerated
    return ((2).dot(A))
AttributeError: 'int' object has no attribute 'dot'
>>> import inspect
>>> print(inspect.getsource(f))
def _lambdifygenerated(A):
    return ((2).dot(A))

```

Hints from issue discussion:
As far as lambdifying matrix expressions, some of the code that I wrote here may be useful https://github.com/ergs/transmutagen/blob/master/transmutagen/codegen.py. 
I am working on this.
The fix for this was incorrect.

Commit message: added more test case

Patch to review:
diff --git a/sympy/printing/pycode.py b/sympy/printing/pycode.py
index fd70c73ab2e5..b22b709f571b 100644
--- a/sympy/printing/pycode.py
+++ b/sympy/printing/pycode.py
@@ -7,7 +7,7 @@
 
 from collections import defaultdict
 from itertools import chain
-from sympy.core import S, Number, Symbol
+from sympy.core import S, Number, Symbol, Mul, Add
 from .precedence import precedence
 from .codeprinter import CodePrinter
 
@@ -493,8 +493,8 @@ def _print_seq(self, seq):
 
     def _print_MatMul(self, expr):
         "Matrix multiplication printer"
-        if isinstance(S(expr.args[0]), (Number, Symbol)):
-            return '({0})'.format(').dot('.join([self._print(expr.args[1]), self._print(expr.args[0])]))
+        if isinstance(expr.args[0], (Symbol, Number, Mul, Add)):
+            return '({0})'.format(').dot('.join(self._print(i) for i in expr.args[1::-1]))
         return '({0})'.format(').dot('.join(self._print(i) for i in expr.args))
 
     def _print_MatPow(self, expr):
diff --git a/sympy/utilities/tests/test_lambdify.py b/sympy/utilities/tests/test_lambdify.py
index 618ffac683fe..208341f05dc5 100644
--- a/sympy/utilities/tests/test_lambdify.py
+++ b/sympy/utilities/tests/test_lambdify.py
@@ -1130,6 +1130,22 @@ def test_issue_15827():
     if not numpy:
         skip("numpy not installed")
     A = MatrixSymbol("A", 3, 3)
-    f = lambdify(A, 2*A)
+    B = MatrixSymbol("B", 3, 2)
+    C = MatrixSymbol("C", 2, 3)
+    k=symbols("k")
+    f = lambdify(A, (2*k)*A)
+    g = lambdify(A, (2+k)*A)
+    h = lambdify(A, 2*A)
+    i = lambdify((A, B), 2*A*B)
     assert numpy.array_equal(f(numpy.array([[1, 2, 3], [1, 2, 3], [1, 2, 3]])), \
+    numpy.array([[2*k, 4*k, 6*k], [2*k, 4*k, 6*k], [2*k, 4*k, 6*k]], dtype=object))
+
+    assert numpy.array_equal(g(numpy.array([[1, 2, 3], [1, 2, 3], [1, 2, 3]])), \
+    numpy.array([[k + 2, 2*k + 4, 3*k + 6], [k + 2, 2*k + 4, 3*k + 6], \
+    [k + 2, 2*k + 4, 3*k + 6]], dtype=object))
+
+    assert numpy.array_equal(h(numpy.array([[1, 2, 3], [1, 2, 3], [1, 2, 3]])), \
     numpy.array([[2, 4, 6], [2, 4, 6], [2, 4, 6]]))
+
+    assert numpy.array_equal(i(numpy.array([[1, 2], [1, 2], [1, 2]]), numpy.array([[1, 2, 3], [1, 2, 3]])), \
+    numpy.array([[2, 4], [2, 4], [2, 4]]))


Code review comments:
diff_hunk: @@ -1130,6 +1130,22 @@ def test_issue_15827():
     if not numpy:
         skip("numpy not installed")
     A = MatrixSymbol("A", 3, 3)
-    f = lambdify(A, 2*A)
+    B = MatrixSymbol("B", 3, 2)
+    C = MatrixSymbol("C", 2, 3)
path: sympy/utilities/tests/test_lambdify.py
text: @user1:
I would use shapes that are only valid in one order. Like (2, 3), (3, 4), (4, 5). Also it would be good to test a product of at least three matrices.