18
$\begingroup$

When working with symbolic matrix operations or other objects which don't have commutative multiplication, it would be nice to not have to constantly switch out times for NonCommutativeMultiply (**). So I was wondering if there is a way to do something like

matrix /: Times[pre___, a_matrix, post___] :=  NonCommutativeMultiply[pre, a, post]
a = matrix["a"];
b = matrix["b"];

and then have it replaced automatically. However since Times is orderless, this doesn't preserve the order. In general, is it impossible to get the order of inputs when doing this kind of "overloading" though upvalues of an orderless function?

$\endgroup$
1
  • $\begingroup$ Check out this answer to my question about block inversion. A package called NCAlgebra may help. $\endgroup$
    – Eli Lansey
    Commented May 11, 2012 at 10:25

4 Answers 4

16
$\begingroup$

Well, you can sort of do this, by creating something like a continuation. This requires playing games with the Stack, and I don't claim that it is robust, but it may represent some theoretical interest, particularly to those of us looking for ways to implement continuations in Mathematica. Here is the code (edit please note that I had to add Update[matrix] to address some improper behavior noted in the comments end edit):

ClearAll[matrix, inMatrix];
matrix /: HoldPattern[Times[pre___, a_matrix, post___]] :=
  (
      Update[matrix];
      ReleaseHold[NonCommutativeMultiply @@@ $stack]
  );
matrix[args__] /; ! TrueQ[inMatrix] :=
  Block[{inMatrix = True},
    Update[matrix];
    $stack = Stack[_][[-5]];
    matrix[args]]

It combines UpValues, Villegas-Gayley trick to redefine a function, and manipuations with Stack. What happens is that first, of course, the attributes of Times are applied, I can't fight that. Then, the DownValues of matrix are applied, and at this point I record the relevant part of the Stack. Then, UpValues of matrix are applied, and at that point I communicate the recorded part of the stack, where the attributes of Times weren't yet applied, and Times gets replaced with NonCommutativeMultiply, after which I re-evaluate this, as if it was not evaluated before. The Update sommand is used to prevent caching the values for the $stack, as this is inappropriate here and resulted in some erroneous behavior noted in the comments.

Here are some examples:

a = matrix["a"];
b = matrix["b"];

a*c*b

matrix[a]**c**matrix[b]

f[g[1 + c*a*d*b*e]]

f[g[1 + c ** matrix["a"] ** d ** matrix["b"] ** e]]

I would not probably recommend such tricks for serious use, it is just interesting that you can use them to divert evaluation sequence in ways which seem to be impossible otherwise.

$\endgroup$
6
  • $\begingroup$ I tried to put something like this together and failed. Once again you prove your mastery. :-) $\endgroup$
    – Mr.Wizard
    Commented May 11, 2012 at 21:14
  • $\begingroup$ @Mr.Wizard Well, thanks, but I am not really sure that actually using this code is a good idea. It may not be robust enough. I just like this direction of thought. $\endgroup$ Commented May 11, 2012 at 21:16
  • $\begingroup$ Really really cool. I never looked at Stack[] before, but was hoping something like this would be possible. Now comes the follow up question, how do you break it, or really when does this go horribly wrong? $\endgroup$
    – jVincent
    Commented May 11, 2012 at 21:17
  • $\begingroup$ @jVincent I wasn't able to break this with a few tests, but I think it should be possible, and I did not try hard enough. For one thing, all code inside Times will be executed twice, and so if it contains side effects, those would also happen twice. But I think one can probably break this even more severely. For symbolic expressions, though, it may be ok. $\endgroup$ Commented May 11, 2012 at 21:24
  • 1
    $\begingroup$ @jVincent Yes you are right, but this is rather subtle. The value of the $stack was cached and not re-computed as it should've been. Fixed now - I added the Update statements in appropriate places. $\endgroup$ Commented May 14, 2012 at 7:02
5
$\begingroup$

there is a package called NCAlgebra I used some time ago to handle non-commutative variables (not just in matrix representation but also quaternions etc) in a multitude of situations.

http://www.math.ucsd.edu/~ncalg/

I think it would solve your problem as it defines its own substitution and expansion rules. You get the option to define a variable as non-commutative and then "do stuff" to it. In your example, and using this package

SetNonCommutative[A, B]

would define A, B to be treated as non-commutative symbols and the order in multiplication will be preserved.

$\endgroup$
8
  • $\begingroup$ Looking thought the example notebooks from this package, it appears that they just use NonCommutativeMultiply exclusively, and provide an external framework for doing other manipulations. $\endgroup$
    – jVincent
    Commented May 11, 2012 at 10:45
  • $\begingroup$ Yes, this is correct. But Mathematica cannot handle expansions in NonCommutativeMultiply and you'd need to type long expressions with **s yourself. I thought that's what triggered the question in the first place (?) $\endgroup$
    – gpap
    Commented May 11, 2012 at 10:51
  • $\begingroup$ No, what triggered my question is just the annoyance at the fact that Times being defined as orderless in general makes it seamingly impossible to make it non orderless in individual cases based no the elements. Mathematically the communicative nature of multiplication is dependent on the elements, not the operator, I was hoping for some clever fix that didn't involve hunting down every single occurance of times, and replacing it, or blocking it out in order to retain order information. $\endgroup$
    – jVincent
    Commented May 11, 2012 at 10:56
  • $\begingroup$ I see - in that case my answer is useless. So, in your example above, if you wanted multiplication over Z4 you would define a z4 "times" that would give you z4[a] z4[b]=Mod[a,b,4] but in your case wouldn't that transpose the problem into defining all your elements of z4 in an expression? $\endgroup$
    – gpap
    Commented May 11, 2012 at 11:27
  • $\begingroup$ Naturally, but lets assume you have a large collection of functions that do things like f[a_,b_]:=a+b-b^2-b*a, or similar. Suddenly all of these expression would obay the nocommutativity of the newly defined matrix objects, if you called f[matrix[a],matrix[b]]. Really what I want is to have the evaluation depending on the upvalues of the members, but that's not possible, since Times is orderless independent of what it's used on. $\endgroup$
    – jVincent
    Commented May 11, 2012 at 12:38
4
$\begingroup$

As far as I know this cannot be made to work in the manner you show so long as the Orderless property of Times remains, because this property is applied before pattern rules are applied.

You can of course do things such as Blocking Times but I cannot think of a way to get (automatically) the behavior you desire without bad side effects.

$\endgroup$
2
$\begingroup$

What you want to do is tricky. You are mixing two things:

  1. You want noncommutative products based on upvalues of the symbols involved;
  2. You want to be able to replace the symbols by matrices.

Both can be achieved with NCAlgebra. The latest distribution is available from:

https://github.com/NCAlgebra/NC

The example from one of your comments in NCAlgebra would look like this:

<< NC`
<< NCAlgebra`
f[a_, b_] := a + b - b^2 - b ** a

Because a and b are noncommutative by default,

f[a, b]

results in

a + b - b ** a - b ** b

whereas

f[A, b]

results in

A + b - A b - b ** b

The second ** gets downgraded to a regular Times because A is commutative. This accomplishes task 1.

The task 2. is more subtle. If you want to substitute a and b for matrices you can use NCMatrixReplaceAll. For example:

AA = {{1, 2}, {3, 4}}
BB = {{-1, 0}, {1, 2}}

and

NCMatrixReplaceAll[f[a, b], {a -> AA, b -> BB}]

would result in

{{0, 4}, {-4, -8}}

which is what you get out of AA + BB - BB.BB - BB.AA, as you might expect. Note that the regular RepleceAll (\.) will fail because of the way Mathematica mixes Lists with other expressions when Plus is involved. This is why f[AA,BB] would also fail.

NCMatrixReplaceAll also works with matrices that have noncommutative entries. For example:

AA = {{1, d}, {c, 4}}
BB = {{a, b}, {1, d}}
NCMatrixReplaceAll[f[a, b], {a -> AA, b -> BB}]

returns

{{1 - b - a ** a - b ** c, -3 b + d - a ** b - a ** d - b ** d}, {-a + c - d - d ** c, 4 - b - 4 d - d ** d}}

which is what you would obtain from AA + BB - NCDot[BB, BB] - NCDot[BB, AA].

$\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.