Why don't * and ^ work as I expected on matrices? [closed]

For example, this input...

{{1, 2}, {3, 4}}*{{1, 2}, {3, 4}}


produces this output...

{{1, 4}, {9, 16}}


and this input...

{{1, 2}, {3, 4}}^2


produces the same...

{{1, 4}, {9, 16}}


What I want in both cases is...

{{7, 10}, {15, 22}}


I think I know what's going on here. Mathematica doesn't seem to be discriminating between lists of lists, and matrices, and the * and ^ operators are just threading over the lists.

I've found . and MatrixPower which do what I think * and ^ should.

But the question still remains, is this confusing (to at least me) behavior of * and ^ by design, and what benefit does it confer?

• @Harold, note that . is (almost) the usual mathematical center-dot notation for matrix product. And that a superscript such as ^2 would be ambiguous when applied to matrices; only context or convention would dictate that it means matrix power, which is made explicit by MatrixPower. Commented Sep 29, 2013 at 17:09
• +1 I had the same question long time ago, but I decided to move on and take it as given... Commented Oct 1, 2013 at 2:10
• Simple answer: Because you have the wrong expectations. The syntax is defined in the language. And its creator had a taste different from the creator of, say, MATLAB. Commented Jul 15, 2018 at 13:45

Matrices in Mathematica are nothing but a specific type of list of lists — specifically, a two dimensional list of lists.

* is the short form for the Times function, which threads over lists elementwise, and this is what you'd use if you wanted to take the Hadamard product of two matrices. So when you say A*B, you're actually saying Times[A, B].

. on the other hand, is short form for Dot, which lets you take the usual matrix products. So A.B is equivalent to Dot[A, B]. Both of these are different and it just boils down to understanding and remembering the short forms and the functions they represent.

If you're coming from a language like MATLAB, you might be confused at first, because * and ^ indeed do behave the way you described in that language. Although one should familiarize themselves with each language's differences, this might help you in remembering it — * and ^ behave exactly like .* and .^ respectively in MATLAB, in that they operate element wise.

Whether it is intuitive or not depends on your personal preferences (and experience with other languages). In the same vein, you could also ask why Infix is ~, when MATLAB treats it as the not operator or throwaway variable, depending on how you use it :)

• For the MATLAB people: * and ^ in Mathematica act like, respectively, .* and .^ in MATLAB (in MATLAB parlance, they are array operators and not matrix operators); this is because * and ^ have the Listable attribute. Commented Jan 24, 2012 at 15:16
• Great explanation on the comparison between Mathematica and MATLAB! Commented Oct 1, 2013 at 2:12

This is by design, because a list of list does not necessarily describe a matrix. Operations like addition, multiplication and power spread over lists without caring what those lists contain. Note that if this would not be so, it might lead to very strange behaviour:

list = {a,a}
lsq = list*list
(*
hypothetical result: 2*a^2
*)
a = {1,1}
lsq
(*
hypothetical result: 4 (because the scalar product of (1,1) with itself is 2)
*)


but

list = {a,a}
a = {1,1} (*now list evaluates to {{1,1},{1,1}}*)
lsq = list*list
(*
hypothetical result: {{2,2},{2,2}} (the square of the matrix {{1,1},{1,1}})
*)


With the current rules both give the same result (namely {{1,1},{1,1}}).

Moreover, the standard multiplication is commutative, while matrix multiplication is not. Therefore you'd get wrong results with expressions like A*B*A^-1 where A and B are intended to be matrices, but are symbols.Mathematica could not know that you intend them to be matrices, and therefore it would simplify this to B, which in general would be wrong if A and B are matrices.

The only way to solve this while using * for matrix multiplication would be to have a type system where you can define a symbol to stand for a certain type. But that's not the way Mathematica works.

• Good points. The only way to get them to work that way, would be to construct objects using UpValues. It's just easier to use Dot and be done with it. Commented Jan 24, 2012 at 3:39

Putting aside language-specific subtleties such as multidimensional arrays and listability of operations, the situation is basically this:

There are two common product operations people do on matrices:

• matrix product

There are three simple approaches one can take to differentiate between these:

1. Use a different operator to describe two two different operations. Most programming languages take this approach.

• Mathematica: * for element-wise, . for matrix product
• MATLAB (and other software inspired by it such as Scilab, O-Matrix, etc. and even Julia): .* for element-wise, * for matrix product
• R: * for element-wise, %*% for matrix product
• Euler Math Toolbox: * for element-wise, . for matrix product
2. Do not provide an direct operator for element-wise product, but do provide a function for element-wise operations à la MapThread.

• Maple: * doesn't work for matrices, . is the matrix product, zip(*, A, B) does element-wise operations

• MuPad: * is the matrix product, zip(A, B, *) does element wise operations

3. Let the type of operation be decided solely by the type of operand.

• NumPy is the only system I know of that takes this approach.

matrix(a)*matrix(b) is a matrix product; array(a)*array(b) is an element-wise product; the result of a simple a*b depends on the type of a and b (array or matrix)

One could argue that this design is a result of Python not being designed for numerical computations and not allowing new operations.

As you can see, most systems designed for serious numerical computations take approach 1. Systems from 2. were designed primarily for symbolic computation, and these operations are likely less used. 3. seems to be an outlier and personally I find it very annoying because I need to remember what type each variable is (but then I don't use numpy a lot).

Mathematical notation, which is intended for people and not computers, is a mix of all of these. But it heavily relies on context and a human's ability to disambiguate.