# Decomposing a matrix with polynomial elements into a polynomial with matrix coefficients

Let's say I have a matrix, $\mathbf{M}$, that is polynomially dependent on a single variable, such as

M = {{15 + a^2, a + 5 a^2}, {a - 5 a^2, 2}}


and I want to find the individual matrices, $\mathbf{A}_i$, such that

$$\mathbf{M} = \mathbf{A}_0 + a \mathbf{A}_1 + a^2 \mathbf{A}_2 + \ldots$$

How do I do this? What do I use if there are multiple variables? Also, can I specify that certain symbols are not to be treated in this manner, e.g.

M = {{15 + a^2, a + 5 a^2}, {a - 5 a^2, 2 c}}


where the constant matrix would be {{15, 0}, {0, 2 c}}? Ideally, this should be applicable to vectors and tensors, also.

-
Note: this is intended to be a canonical question. – rcollyer Jun 29 '12 at 14:25
Consider e.g. M = {{ArcTan[a], Zeta[a]}, {Sinh[a], Sqrt[a]}}. The only route seems to be expanding every entry in Taylor series. – Artes Jun 29 '12 at 14:35
@Artes you are correct, but I was honestly focusing on polynomial dependent matrices. – rcollyer Jun 29 '12 at 14:37
@Artes had the right idea: Taylor coefficients are what I basically use in my answer. – Jens Jun 29 '12 at 15:08

Here is a very simple way to do it:

Table[1/i! D[M, {a, i}] /. a -> 0, {i, 0, 3}]

(*
==> {{{15, 0}, {0, 2}}, {{0, 1}, {1, 0}}, {{1, 5}, {-5, 0}}, {{0, 0}, {0, 0}}}
*)


This works even if the entries are not polynomials. If they are, you can replace the arbitrary maximum 3 in the Table index by the degree of the polynomial:

Max[Exponent[M, a]]


Edit

Looking at the other solutions, this solution (due to its fundamental simplicity) is the only one that works without modification for arbitrary rank tensors and simultaneously for arbitrary functions that can be expanded in the variable a, be they polynomial or not.

-
+1, it hadn't even occurred to me that using a derivative is perfect for this. – rcollyer Jun 29 '12 at 15:08
Alternatively: Table[Map[SeriesCoefficient[#, {a, 0, i}] &, M, {2}], {i, 0, 3}]. – J. M. Jun 29 '12 at 15:09
@J.M. I think that should be posted as an answer. – Mr.Wizard Jun 30 '12 at 7:44
Accepted for simplicity and generality beyond what I asked for. – rcollyer Jul 1 '12 at 14:06

Here's one quick way for polynomial matrices:

polyMat = {{15 + a^2, a + 5 a^2}, {a - 5 a^2, 2}};

{{{15, 0}, {0, 2}}, {{0, 1}, {1, 0}}, {{1, 5}, {-5, 0}}}


Alternatively (as Jens hints), you can do Flatten[PadRight[CoefficientList[polyMat, a]], {3}].

You can check that the matrix polynomial is reproduced with Fold[(#1 a + #2) &, 0, Reverse @ %].

-
It works (+1)... but it's a bit complicated. – Jens Jun 29 '12 at 15:02
Because of the Transpose[]? ;) – J. M. Jun 29 '12 at 15:14
Yes, you could have replaced Transpose by Flatten... OK - better not. – Jens Jun 29 '12 at 15:20
I see. The thing is that I'm comfy with the second argument of Transpose[] for as long as I'm dealing with tensors of rank $\leq 3$. More than that, and it's a tad complicated for me to imagine, too... – J. M. Jun 29 '12 at 15:44
I've modified it so that one no longer needs to deal with the polynomial degree explicitly... – J. M. Jun 29 '12 at 18:03

First, if you don't know the degree you can compute it:

m =  {{15 + a^5, a + 5 a^2}, {a - 5 a^2, 2 c}};
degree = Max[Flatten[Exponent[#, {a}] & /@ Flatten[m]]]


(I have increased the degree of m to verify that intermediate zero matrices are correctly output.)

And now, with degree in hand, why not use a function intended for this task?

 Coefficient[m, a, #] & /@ Range[0, degree]


It works for tensors of any rank, including scalars.

-
As I mentioned in a previous version of answer, Max[Exponent[m, a] seems a bit more compact for computing the degree... – J. M. Jun 29 '12 at 17:38
And, you get my last vote for today, +1. – rcollyer Jun 29 '12 at 17:57
@J.M. Yes, it is more compact: thanks. (You refer to your old answer. I like the new one.) – whuber Jun 29 '12 at 18:05
Yes; I fixed my comment now too... :D – J. M. Jun 29 '12 at 18:10

This is similar to J. M.'s solution, but generalized to rank $n$ tensors.

Clear[decomposePolyMat]
decomposePolyMat[m_, var_] :=
Module[{rank = ArrayDepth@m, coeffs = CoefficientList[m, var],len},
len = Max@Map[Length, coeffs, {rank}];
Flatten[Map[PadRight[#, len] &, coeffs, {rank}], {rank + 1}]
]

-
Length @ Dimensions @ m is so common an operation that there is in fact a built-in function for this operation: ArrayDepth[] (formerly TensorRank[]). – J. M. Jun 29 '12 at 15:11