6
$\begingroup$

In writing my own (noncommutative) product I want to avoid typing redundant symbols like A.B.C or A**B**C, I just want to type A B C and have that mapped to my own Product[A,B,C]. (call me a purist)

1. Is there a clever way to avoid A B C being mapped to Times[A,B,C] (besides ClearAll[Times])?

2. Is there any documentation about the inner workings of (Pre-)Parsing and Times?

$\endgroup$
4
  • 2
    $\begingroup$ Why do you think ClearAll[Times] would work? $\endgroup$
    – rm -rf
    Sep 29, 2012 at 18:00
  • $\begingroup$ It will not. That was just a rhetoric side note. $\endgroup$
    – NoEscape
    Sep 30, 2012 at 5:36
  • $\begingroup$ @rm-rf : please note, this is a Q&A site, not a Q&Q site!!! $\endgroup$
    – NoEscape
    Oct 1, 2012 at 17:14
  • $\begingroup$ @NoEscape but the FAQ says that comments should be used to help clarify the questioner's thoughts... So this is a Q, C, and A site really... $\endgroup$
    – cormullion
    Oct 1, 2012 at 17:28

3 Answers 3

8
$\begingroup$

What I usually suggest for such cases is to use custom environments, inside which you can change the rules of the game. Here is a lexical one for your case:

ClearAll[withNCTimes];
SetAttributes[withNCTimes, HoldAll];
withNCTimes[code_] :=
    Unevaluated[code] /. Times -> NonCommutativeMultiply

so that

withNCTimes[a*b*c]

(*  a**b**c  *)

and here is the dynamic one:

ClearAll[withNCTimesDyn];
SetAttributes[withNCTimesDyn, HoldAll];
withNCTimesDyn[code_] :=
  Block[{Times =  NonCommutativeMultiply},
     code];

which would, for the example above, produce the same result.

Dynamic environments are more dangerous since they affect the full evaluation stack, but also more general. Lexical environments are safer, since their action is lexically localized to code you have inside of them. But, if that code contains function calls where Times is used, those invocations of Times won't be affected by the environment, since they are not literally present in the piece of code around which you wrap the environment. I discussed this in a little more detail here.

If you don't want to type the name of an environment every time, you can, in the FrontEnd session, automate that by utilizing $Pre:

$Pre = withNCTimes;
a*b*c

(* a**b**c *)

$Pre =. 

Finally, I would never attempt to overload Times (or Plus etc), since these functions are very fundamental to the system, and there is no telling what can happen if you do that. Even for more specialized functions, their overloading can lead to quite strange and unwanted behavior, see e.g. here.

$\endgroup$
10
  • $\begingroup$ @rm-rf It must be possible along the same lines as in my answer above, just more complicated rules. $\endgroup$ Sep 29, 2012 at 20:16
  • $\begingroup$ @ rm-rf: My comment was just intended to mean that I'm still going to to use Times, as for example MyProduct[A,b,C] will be converted to Times[b,MyProduct[A,C] if b is a Number or has a Scalar property. so, i still need Times - internally - not in input => i cannot modify Times to always map to MyProduct because this will lead to recursion $\endgroup$
    – NoEscape
    Sep 30, 2012 at 5:00
  • $\begingroup$ thx^2 to Leonid, your answer just opened a door for me! $\endgroup$
    – NoEscape
    Sep 30, 2012 at 5:01
  • $\begingroup$ Thx for mentioning the $Pre=. command. It should also be put before the lines ClearAll[withNCTimes]; or ClearAll[withNCTimesDyn]; in the code above, otherwise all input will be messed up if the definitions are executed a second time. $\endgroup$
    – NoEscape
    Sep 30, 2012 at 5:32
  • 1
    $\begingroup$ @NoEscape It is probably possible. Conceptually, it is also better, because what you basically want is to change the syntax. However, all these approaches are incomplete. Generally you want something like a programmable language preprocessor, which Mathematica does not have. I discussed these matters in a little more detail in my answer here. $\endgroup$ Oct 1, 2012 at 13:16
2
$\begingroup$

I would strongly recommend that you not follow this approach. It is not a good idea to modify built-ins, especially something as fundamental as Times as this could lead to unintended consequences elsewhere. Instead, I would suggest that you utilize one of the many infix operators without any pre-defined meaning.

That said, you could do something like:

Unprotect@Times;
Times[x__Symbol] := MyProduct[x]
Protect@Times;

X Y Z
(* MyProduct[X, Y, Z] *)

This acts only on symbols, so multiplication of numbers and variables with OwnValues still work as usual.

$\endgroup$
4
  • $\begingroup$ Right, I'm trying to avoid modifying Times[], as you recommend and as it is self-evident. (I'm a novice to StackExchange, not to programming) E.g. I still want to use Times[a,MyProduct[A,B]] for certain a's, which will besome impossible/recursive with your code. $\endgroup$
    – NoEscape
    Sep 29, 2012 at 19:13
  • $\begingroup$ I need something that acts on the notation/input side only. Like Notation[ [a_ b_ c_] <=> MyProduct[a_,b_,c_] ], but this will not work, because the internal Times Notation is at work FIRST! $\endgroup$
    – NoEscape
    Sep 29, 2012 at 19:25
  • $\begingroup$ @NoEscape Times is one of the few functions where built-ins definitions are always read first before custom definitions. This is in the "More info" section of the docs. As such, I highly doubt it might be possible to do something along the lines of what you want... I could be wrong, but it's beyond me. $\endgroup$
    – rm -rf
    Sep 29, 2012 at 19:33
  • $\begingroup$ @rm-rf Well, sometimes things like this are possible. I am not sure though I'd recommend that. $\endgroup$ Sep 29, 2012 at 20:02
1
$\begingroup$

I'm not sure how useful this is in your redundancy-free setting or at all, but I assume you don't want the non-commutative multiplication to happen everywhere. When you wrap your special data-type like for instance this M[data] than another approach would be possible

M /: Times[M[a_], M[b_]] := M[MyProduct[a, b]]

and you get the special multiplication only for your special data-structure

Mathematica graphics

You maybe shouldn't use M but something like \[ScriptCapitalM] which you can input fast but which is less likely to be already defined.

$\endgroup$
1
  • $\begingroup$ Already tried a similar thing. This will immediately fail if someone types M[a] A M[b], so we'd have to define all kinds of combos... $\endgroup$
    – NoEscape
    Sep 30, 2012 at 9:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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