Repository: sympy/sympy

Issue:
MatMul's coeff is not working. It throws an error about args_cnc.
I get an error when I try to take a "coeff" on a matrix.

``` python
from sympy import *
N = Symbol("N", integer=True)
x1 = Symbol("x1")
M1 = MatrixSymbol("M1", N, N)
M2 = MatrixSymbol("M2", N, N)
z = (M2 + 2 * (M2 + Identity(N)) * M1 + Identity(N))
z.coeff(M1)
```
leads to
```
Traceback (most recent call last):
  ...
AttributeError: 'list' object has no attribute 'difference'

```

For example, define the following function ...

```python
def _MatMul_fixed_args_cnc (self, cset=False, warn=True, split_1=True):
  c = [x for x in self.args if x.is_commutative]
  nc = [x for x in self.args if not x.is_commutative]
  if cset:
    clen = len(c)
    c = set(c)
    if clen and warn and len(c) != clen:
      raise ValueError('repeated commutative arguments: %s' %
                       [ci for ci in c if list(self.args).count(ci) > 1])
  return [c, nc]

def fix_MatMul_args_cnc ():
  MatMul.args_cnc = _MatMul_fixed_args_cnc
```

If you use it, it will work.

``` python
>>> fix_MatMul_args_cnc()
>>> z.coeff(M1)
2*I + 2*M2

```

With matrices, taking the coeff from the left and taking it from the right have different meanings, so I thought it might be what you intended to throw an exception, so I didn't make a pull request. I also don't want to use pull requests because I'm not familiar with GitHub and I don't speak English well.

Discussion:
sympy-bot: :white_check_mark:

Hi, I am the [SymPy bot](https://github.com/sympy/sympy-bot) (v167). I'm here to help you write a release notes entry. Please read the [guide on how to write release notes](https://github.com/sympy/sympy/wiki/Writing-Release-Notes).



* No release notes entry will be added for this pull request.

<details><summary>Click here to see the pull request description that was parsed.</summary>

    <!-- 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://tinyurl.com/auto-closing for more information). Also, please
    write a comment on that issue linking back to this pull request once it is
    open. -->

    Fixes #23519

    #### Brief description of what is fixed or changed

    Extended MarMul.args_cnc to support the `cset` argument and return a set which is required to fix #23519 

    #### Other comments


    #### Release Notes

    <!-- Write the release notes for this release below between the BEGIN and END
    statements. The basic format is a bulleted list with the name of the subpackage
    and the release note for this PR. For example:

    * solvers
      * Added a new solver for logarithmic equations.

    * functions
      * Fixed a bug with log of integers.

    or if no release note(s) should be included use:

    NO ENTRY

    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 -->
    NO ENTRY
    <!-- END RELEASE NOTES -->


</details><p>


Patch:
diff --git a/sympy/matrices/expressions/matmul.py b/sympy/matrices/expressions/matmul.py
index 5e98b7c69b..a11bcb3d3c 100644
--- a/sympy/matrices/expressions/matmul.py
+++ b/sympy/matrices/expressions/matmul.py
@@ -191,9 +191,15 @@ def doit(self, **kwargs):
         return expr
 
     # Needed for partial compatibility with Mul
-    def args_cnc(self, **kwargs):
+    def args_cnc(self, cset=False, warn=True, **kwargs):
         coeff_c = [x for x in self.args if x.is_commutative]
         coeff_nc = [x for x in self.args if not x.is_commutative]
+        if cset:
+            clen = len(coeff_c)
+            coeff_c = set(coeff_c)
+            if clen and warn and len(coeff_c) != clen:
+                raise ValueError('repeated commutative arguments: %s' %
+                                 [ci for ci in coeff_c if list(self.args).count(ci) > 1])
         return [coeff_c, coeff_nc]
 
     def _eval_derivative_matrix_lines(self, x):


Test patch:
diff --git a/sympy/matrices/expressions/tests/test_matmul.py b/sympy/matrices/expressions/tests/test_matmul.py
index 5a1b8014ae..e3126c8ae4 100644
--- a/sympy/matrices/expressions/tests/test_matmul.py
+++ b/sympy/matrices/expressions/tests/test_matmul.py
@@ -168,3 +168,12 @@ def test_construction_with_mul():
 def test_generic_identity():
     assert MatMul.identity == GenericIdentity()
     assert MatMul.identity != S.One
+
+
+def test_issue_23519():
+    N = Symbol("N", integer=True)
+    M1 = MatrixSymbol("M1", N, N)
+    M2 = MatrixSymbol("M2", N, N)
+    I = Identity(N)
+    z = (M2 + 2 * (M2 + I) * M1 + I)
+    assert z.coeff(M1) == 2*I + 2*M2