# Matrix multiplication in Block Form symbolic calculation by Mathematica

I have a problem which requires taking product of two $10\times10$ matrices. I would like to do it by considering both matrices as $5\times5$ matrices such that each entry of both matrices is actually a $2\times2$ matrix; moreover, there are variables so this is a symbolic calculation. (Side remark: matrix multiplication is not a commutative operation, i.e. $AB\neq BA$ in general.) Does anyone know how to perform this block form multiplication in Mathematica, or using any other software?

-

Welcome! I added $\LaTeX$ markup to your question to make it read better. In the future, you can do the same by wrapping inline equations with `$` and `$$` to provide block style equations. If you have any questions about the operation of this site, please check out the FAQ, and the meta site. – rcollyer Jul 5 '12 at 2:17
Got you! Thanks! – Danny Jul 5 '12 at 2:54
Take a look at the (free) NCAlgebra package, see e.g. here: mathematica.stackexchange.com/questions/8/… You'll need it when doing more general operation on the block form of matrices.  I'll post an answer if/when I have the time. – Szabolcs Jul 5 '12 at 7:27
@Szabolcs: Thanks! I will bear this package in mind. Right now I am trying the function blockMultiply – Danny Jul 5 '12 at 16:39

## 2 Answers

If I understand correctly, the main issue in your question is how to make a `Dot` product of two block matrices such that the result preserves the order of the factors in the resulting block matrix, because the entries are non-commuting matrices themselves.

The problem is that the result of `Dot` has multiplications of the matrix components in it, and this corresponds to the operation `Times` which is orderless. `Dot` preserves the order of its factors, but `Times` always sorts its factors lexicographically, i.e., in a standard sorting order so that `z*b` becomes `b*z` and `m[2]*m[1]` becomes `m[1]*m[2]`, etc.

If one were to use the `Dot` function for the matrix multiplication, one would have to track in what way the order of the input factors is changed when brought into the lexicographical order of `Times`, and then undo that sorting.

Edit

As Mr. Wizard pointed out, it is best to us a generalization of `Dot` that doesn't apply `Times` to the components at all:

````blockMultiply[mats__] := Inner[Dot, mats]
````

End edit

To show how this works, let's first define two $5\times 5$ matrices called `smallMatrix[[1]]` and `smallMatrix[[2]]`. I define them in one go, and show them afterwards:

````smallMatrix = Table[Array[{"A", "B"}[[i]], {5, 5}], {i, 2}];

MatrixForm[smallMatrix[[1]]]
````

$\left( \begin{array}{ccccc} \text{A}(1,1) & \text{A}(1,2) & \text{A}(1,3) & \text{A}(1,4) & \text{A}(1,5) \\ \text{A}(2,1) & \text{A}(2,2) & \text{A}(2,3) & \text{A}(2,4) & \text{A}(2,5) \\ \text{A}(3,1) & \text{A}(3,2) & \text{A}(3,3) & \text{A}(3,4) & \text{A}(3,5) \\ \text{A}(4,1) & \text{A}(4,2) & \text{A}(4,3) & \text{A}(4,4) & \text{A}(4,5) \\ \text{A}(5,1) & \text{A}(5,2) & \text{A}(5,3) & \text{A}(5,4) & \text{A}(5,5) \\ \end{array} \right)$

````MatrixForm[smallMatrix[[2]]]
````

$\left( \begin{array}{ccccc} \text{B}(1,1) & \text{B}(1,2) & \text{B}(1,3) & \text{B}(1,4) & \text{B}(1,5) \\ \text{B}(2,1) & \text{B}(2,2) & \text{B}(2,3) & \text{B}(2,4) & \text{B}(2,5) \\ \text{B}(3,1) & \text{B}(3,2) & \text{B}(3,3) & \text{B}(3,4) & \text{B}(3,5) \\ \text{B}(4,1) & \text{B}(4,2) & \text{B}(4,3) & \text{B}(4,4) & \text{B}(4,5) \\ \text{B}(5,1) & \text{B}(5,2) & \text{B}(5,3) & \text{B}(5,4) & \text{B}(5,5) \\ \end{array} \right)$

Now I multiply these matrices under the assumption that each of their entries is itself a (so far unspecified) matrix:

````productAB = blockMultiply[smallMatrix[[1]], smallMatrix[[2]]];
productBA = blockMultiply[smallMatrix[[2]], smallMatrix[[1]]];
````

If you inspect these result matrices you'll see that the order of the factors is correct, and each element is a sum of (matrix) `Dot` products. The results are too large to display here.

Another way to check that this works is to insert an actual pair of $10\times 10$ matrices by writing them as block matrices. I first define the big two-dimensional matrices and then use `Partition` to subdivide them into blocks of size $2\times 2$:

````bigMatrix = Table[Array[{"a", "b"}[[i]], {10, 10}], {i, 2}];
blockMatrix = Table[Partition[bigMatrix[[i]], {2, 2}], {i, 2}];

MatrixForm[blockMatrix[[1]]]
````

and similarly for `MatrixForm[blockMatrix[[2]]]`.

Now we use these big matrices in the results obtained above with `blockMultiply`:

````AB = Flatten[
   productAB /. Thread[
     Flatten[smallMatrix] -> Flatten[blockMatrix, {{1, 2, 3}}]
     ],
   {{1, 3}, {2, 4}}];

BA = Flatten[
   productBA /. Thread[
     Flatten[smallMatrix] -> Flatten[blockMatrix, {{1, 2, 3}}]
     ],
   {{1, 3}, {2, 4}}];

FullSimplify[AB == bigMatrix[[1]].bigMatrix[[2]]]

(* ==> True *)

FullSimplify[BA == bigMatrix[[2]].bigMatrix[[1]]]

(* ==> True *)
````

This says that the block multiplications yield the same result as doing the matrix products directly (as in `bigMatrix[[1]].bigMatrix[[2]]`). And the order of the multiplications is correctly captured.

The `Flatten` commands appearing in the definition of `AB` and `BA` (for the two different orders of the factors) are perhaps a little hard to see through. With a command like `Flatten[blockMatrix, {{1, 2, 3}}]` one gets a list in which the sub-blocks of the `blockMatrix` appear flattened, so that they can be used in the `Thread` of the `->` which replaces the small symbolic block matrices by the blocks of the big matrix. The `Flatten[ ..., {{1, 3}, {2, 4}}]` removes the block matrix level and creates a $10\times 10$ matrix from the $2\times 2$ blocks.

The function `blockMultiply` is intended to work for any number of arguments in a matrix multiplication, and also for any dimension as long as all adjacent factor share a common dimension as required by `Dot`. So you could also repeat the above tests by splitting up the two matrices in `bigMatrix` into $5\times 5$ blocks, for example.

-
Jens, why not ```{a, b} = Table[Array[{"A", "B"}[[i]], {5, 5}], {i, 2}];

Inner[Dot, a, b]
```? – Mr.Wizard♦ Jul 5 '12 at 7:02
@Mr.Wizard Because of the lateness of the hour, I guess. Thanks for the simplificiation! – Jens Jul 5 '12 at 7:19

1
Thanks for the credit in the edit. IMHO it would be better to leave out the long `blockMultiply` code as I don't think it is instructive. – Mr.Wizard♦ Jul 5 '12 at 7:34

1
@Mr.Wizard You're right - all those fireworks messed with my brain. – Jens Jul 5 '12 at 14:33

1
the Pyrotechnic Mitigation Plea -- granted. ;^) – Mr.Wizard♦ Jul 5 '12 at 14:44
show 3 more comments

You are talking about tensors, right? Such a tensor can be created with e.g.

````example=Array[e,{5,5,2,2}];
example//MatrixForm
````

All you have to do now, is to take from the example `e[1,1,1,1]` etc. and replace it with the variables you want to use. The same can be done with a second exampleTensor, so that you can work with both of them (multiply etc.).

I hope this helps.

-

Sorry that my post is ambiguous. This is not about tensor - tensor of two $10\times 10$ matrices would be a $100\times 100$ matrix. What I meant was as Jens pointed out in his first two paragraphs. – Danny Jul 5 '12 at 16:48
No problem! Thanks for the feedback! – partial81 Jul 5 '12 at 18:49
lang-mma
{"extraction_info": {"found_math": true, "script_math_tex": 0, "script_math_asciimath": 0, "math_annotations": 0, "math_alttext": 0, "mathml": 0, "mathjax_tag": 0, "mathjax_inline_tex": 15, "mathjax_display_tex": 0, "mathjax_asciimath": 0, "img_math": 0, "codecogs_latex": 0, "wp_latex": 0, "mimetex.cgi": 0, "/images/math/codecogs": 0, "mathtex.cgi": 0}, "config": {"markdown_headings": true, "markdown_code": true, "boilerplate_config": {"ratio_threshold": 0.18, "absolute_threshold": 10, "end_threshold": 15, "enable": true}, "remove_buttons": true, "remove_image_figures": true, "remove_link_clusters": true, "table_config": {"min_rows": 2, "min_cols": 3, "format": "github"}, "remove_chinese": true, "remove_edit_buttons": true, "extract_latex": true}, "english_confidence": 0.9089102149009705, "perplexity_flag": "middle"}