Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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?

share|improve this question
    
Check out this answer to my question about block inversion. A package called NCAlgebra may help. –  Eli Lansey May 11 '12 at 10:25
add comment

3 Answers 3

up vote 10 down vote accepted

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.

share|improve this answer
    
I tried to put something like this together and failed. Once again you prove your mastery. :-) –  Mr.Wizard May 11 '12 at 21:14
    
@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. –  Leonid Shifrin May 11 '12 at 21:16
    
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? –  jVincent May 11 '12 at 21:17
    
@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. –  Leonid Shifrin May 11 '12 at 21:24
1  
@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. –  Leonid Shifrin May 14 '12 at 7:02
show 1 more comment

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.

share|improve this answer
add comment

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.

share|improve this answer
    
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. –  jVincent May 11 '12 at 10:45
    
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 (?) –  gpap May 11 '12 at 10:51
    
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. –  jVincent May 11 '12 at 10:56
    
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? –  gpap May 11 '12 at 11:27
    
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. –  jVincent May 11 '12 at 12:38
show 3 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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