# How can I remove the attributes "Orderless" from function Times stably and reliably?

Recently I have been doing some algebra of partitioned matrices, where product like below is common:

where $$A_{11}, A_{12}, X, Y$$ are all partitioned matrix blocks thus all are matrices in essence.

One of the Important features of product between matrices and/or vectors is that: it is not commutative, namely $$AB \neq BA$$, so I have to remove the attributes of "Orderless" from Times[] to make sure the system does not change the order of product terms in result as it would often does.

To do this product in Mathematica, first I cleared the attributes:

ClearAttributes[Times, Orderless];


Then I tried to do this product several times, in order to simulate the long computation process I might need to do on this kind of algebra in the future:

({
{Subscript[A, 11], 0},
{0, Subscript[A, 22]}
}) . ({
{0, Y},
{X, 0}
}) // MatrixForm


However, it was to my surprise to find out that the result is unstable. For the same product, sometimes it will give out the result as:

While sometimes the result given is:

But only the second one is true, where in the relevant products $$A_{11}, A_{12}$$ go first and $$X,Y$$ go last.

The typical situation where the order/sequence of the product changes:

(1) After you do several other calculations and go back to do the same product;

(2) After you take a break for several minutes and come back to do the same product;

(3) When the name of a multiplier is too long, the system tends to adjust the order/sequence of the product to let the multiplier with long name goes last. For example, for matrix X, suppose the correct product is Transpose[X] X or Inverse[X] Xbut the system would tend to give it as X Transpose[X] or X Inverse[X]

So I was wondering: why the result would be so unstable even after the attributes of Orderless already being cleared? Is there anyway to clear the attributes stably and reliably so that when I do the algebra of partitioned matrices it will always gives the product in result in correct order/sequence?

• First of all, the operator . is not Times but Dot. Secondly, I wouldn't mess with the properties of such a fundamental operator. I suggest defining a new operator or using something like NonCommutativeMultiply, for which you can find several examples on StackExchange. Commented Jan 10, 2022 at 9:44
• Thanks Domen, but I would like to clarify: between the two large matrices outside, it is dot product, which does not have the attributes of Orderless by default, but to work out the product in entry level, Dot[] will compute sub-product as entry in result matrices by Times[], that is the why I have to modify Times furthermore to get the correct result. Commented Jan 10, 2022 at 9:52
• I would also recommend against changing a built-in, and maybe define your own version of Dot to use instead—consider using Inner, e.g. a = {{Indexed[A,{1,1}], 0}, {0, Indexed[A, {2,2}]}}; b = {{0,X},{Y,0}}; Inner[NonCommutativeMultiply, a, b, Plus]. Of course, you'd need to define NonCommutativeMultiply appropriately first, since it's nearly completely undefined by default, which is not a trivial task... Commented Jan 10, 2022 at 10:05
• @thorimur That's definitely true, it is indeed not a trivial task since I have been stuck here for nearly one week. For such a seemingly simple thing, the Partitioned Matrix Algebra, it is counter-intuitively hard to teach mathematica to do it correctly, how ironic it is! Commented Jan 10, 2022 at 10:23
• Changing attributes of the low level arithmetic functions Plus, Times and Power ranks high on the list of Things Not To Do. There is past discussion about this here. Generally one instead uses NonCommutativeMultiply, defining rules as needed. Commented Jan 10, 2022 at 15:10

First I assume that you want the outer "multiply to be "Dot" and the inner "Times" with order. (If the inner is also Dot, you must adapt the code inside "Sum")

Redefining Times is dangerous. Instead I would use NonCommutativeMultiply that has no definitions besides being non commutative.

First we define our multiplication operator:

Clear["Globals*"]
Unprotect[NonCommutativeMultiply]
NonCommutativeMultiply[a_, b_] :=
Table[Sum[a[[i1, i2]] b[[i2, i3]], {i2, n}], {i1, n}, {i3, n}]


Then we make a simple test example:

n = 2;
a=Table[RandomInteger[{0,10}],{i1,n},{i2,n},{i3,n},{i4,n}];
b=Table[RandomInteger[{0,10}],{i1,n},{i2,n},{i3,n},{i4,n}];
a // MatrixForm
b // MatrixForm
a ** b // MatrixForm


Update

To make it work with the case where the elements of a and b are symbolic matrices:

Clear["Globals*"]
Unprotect[NonCommutativeMultiply]
NonCommutativeMultiply[a_?MatrixQ, b_?MatrixQ] :=
Table[Sum[a[[i1, i2]] ** b[[i2, i3]], {i2, n}], {i1, n}, {i3, n}]

n = 2;
ma = Array[Subscript[a, #1, #2] &, {n, n}];
mb = Array[Subscript[b, #1, #2] &, {n, n}];

ma // MatrixForm
mb // MatrixForm
ma ** mb // MatrixForm


• Thanks Daniel. By default, mathematica identifies each matrix as one constituting of scalars. So when two matrices make dot produce, the Dot[] will employ Times[] to work out the result entry by entry, that is why when the matrices are made of symbolic matrix blocks or symbolic sub matrices, it is hard to teach mathematica to do the product correctly without commutation. Commented Jan 10, 2022 at 11:35
• Furthermore, Daniel, your solution looks impressive, but it does not work in my case, where the matrices are made of symbolic matrix blocks or symbolic sub matrices like X and Y in my post, and the specific values for each entry in those sub matrices is unknown, what I am doing is pure symbolic calculations. Commented Jan 10, 2022 at 11:50
• I made an update for this case. Note instead of using "Times" I use "**", that is "NonCommutatvve Multiply". This is necessary because otherwise MMA will reorder the terms. Commented Jan 10, 2022 at 12:08

You might want to take a look at some of the support for matrix operations in NCAlgebra. Look for matrices in the documentation. It supports the kind of product you are trying to perform and much more, such as block substitutions.

SetNonCommutative[A, X, Y]


to treat the letters A, X, and Y as noncommutative symbols so that you can operate with the matrices

m1 = {{Subscript[A, 11], 0}, {0, Subscript[A, 22]}}
m2 = {{0, Y}, {X, 0}}


For example, to perform a noncommutative matrix product, use NCDot, as in

NCDot[m1,m2]


which returns

{{0, Subscript[A, 11] ** Y}, {Subscript[A, 22] ** X, 0}}

You can also manipulate products of block matrices and then perform the multiplication. For example

m1 ** m2


results in

{{Subscript[A, 11], 0}, {0, Subscript[A, 22]}} ** {{0, Y}, {X, 0}}

and

NCMatrixExpand[m1 ** m2]


then expands the ** into the appropriate NCDot to produce

{{0, Subscript[A, 11] ** Y}, {Subscript[A, 22] ** X, 0}}

Even more interesting is

m1 ** inv[m2]


which results in

{{Subscript[A, 11], 0}, {0, Subscript[A, 22]}} ** inv[{{0, Y}, {X, 0}}]

and

NCMatrixExpand[m1 ** inv[m2]]


that correctly expands the symbolic block inverse

{{0, Subscript[A, 11] ** inv[X]}, {Subscript[A, 22] ** inv[Y], 0}}

P.S.: We are in the process of updating NCAlgebra so you might want to try our latest beta version from here, which you can install as a paclet.