18
$\begingroup$

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.

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

5 Answers 5

20
$\begingroup$

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.

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

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.

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

Here's one quick way for polynomial matrices:

polyMat = {{15 + a^2, a + 5 a^2}, {a - 5 a^2, 2}};
Transpose[PadRight[CoefficientList[polyMat, a]], {2, 3, 1}]

{{{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 @ %].

$\endgroup$
5
  • $\begingroup$ It works (+1)... but it's a bit complicated. $\endgroup$
    – Jens
    Jun 29, 2012 at 15:02
  • $\begingroup$ Because of the Transpose[]? ;) $\endgroup$ Jun 29, 2012 at 15:14
  • $\begingroup$ Yes, you could have replaced Transpose by Flatten... OK - better not. $\endgroup$
    – Jens
    Jun 29, 2012 at 15:20
  • $\begingroup$ 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... $\endgroup$ Jun 29, 2012 at 15:44
  • $\begingroup$ I've modified it so that one no longer needs to deal with the polynomial degree explicitly... $\endgroup$ Jun 29, 2012 at 18:03
9
$\begingroup$

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}]
     ]
$\endgroup$
1
  • 1
    $\begingroup$ Length @ Dimensions @ m is so common an operation that there is in fact a built-in function for this operation: ArrayDepth[] (formerly TensorRank[]). $\endgroup$ Jun 29, 2012 at 15:11
2
$\begingroup$

Starting in M9, SeriesCoefficient automatically threads:

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

SeriesCoefficient[M, {a, 0, #}]& /@ Range[0, 2]

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

M = {{Sin[x], Cos[x]}, {Exp[x], Tan[x]}};

SeriesCoefficient[M, {x, 0, #}]& /@ Range[0, 2]

{{{0, 1}, {1, 0}}, {{1, 0}, {1, 1}}, {{0, -(1/2)}, {1/2, 0}}}

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.