TeXForm works by creating TraditionalForm
boxes, and then converting those boxes into a TeX string. This means there are two methods to change the TeXForm
format of an expression:
- Change the
TraditionalForm
output
- Change the conversion code that converts
TraditionalForm
boxes into TeX.
I like changing the TraditionalForm
output instead of changing the conversion code, because boxes don't carry context. There may be multiple expressions that produce similar boxes, and if you try to write conversion code after the expression has been turned into boxes you may be affecting expressions that you don't want to modify. It's a little bit like trying to repair a car after an accident vs preventing the accident in the first place.
So, the first step is to figure out how to change the TraditionalForm
of products. Without going into details, this is actually difficult to do, because a variety of different expressions will produce expression that look like space separated terms. So, rather than try to add formatting rules for all of these different expressions, it is much simpler to look for the signature of a product of terms, which is:
RowBox[{a, " ", b, " ", c, ..}]
and then replace all the spaces with the symbol of your choice (in fact, TraditionalForm
already does something like this when it tries to reorder products into a more "TraditionalForm" like order).
Therefore, we want to add a TraditionalForm
formatting rule that post-processes the TraditionalForm
boxes after all other formatting has take place. The way I will implement this is to add a rule that gets fired before any other formatting has occurred. This rule will create the normal TraditionalForm
boxes, and then convert any products into "$\times$" separated products. For this purpose, it will be convenient to make use of my Initial
wrapper, which I repeat here for convenience:
Initial /: Verbatim[TagSetDelayed][Initial[sym_], lhs_, rhs_] := With[
{
new=Block[{sym},
TagSetDelayed[sym,lhs,rhs];
First @ Language`ExtendedDefinition[sym]
],
protect=Unprotect[sym]
},
sym;
Quiet@MakeBoxes[sym[],TraditionalForm];
Unprotect[sym];
Replace[
new,
Rule[values_,n:Except[{}]] :> (
values[sym] = DeleteDuplicates @ Join[n, values[sym]]
),
{2}
];
Protect@protect;
]
Using the Initial
wrapper, the following MakeBoxes
rule will fire before all others:
Initial[TraditionalForm] /: MakeBoxes[e_, TraditionalForm] /; TrueQ@$TeX := Block[{$TeX = False},
ReplaceAll[
MakeBoxes[e, TraditionalForm],
RowBox[b_?productQ] :> RuleCondition @ Replace[RowBox[b], " "->"\[Times]", {2}]
]
]
productQ[b_] := Length[b]>1 && MatchQ[b[[2 ;; -2 ;; 2]], {" "..}]
Let's see this in action:
$TeX = False;
x+2y //TraditionalForm

Versus:
$TeX = True;
x+2y //TraditionalForm

All that remains is to modify the TeXForm
code to block $TeX
to True
when creating the TraditionalForm
boxes. This can again be done using the Initial
wrapper:
Initial[Convert`TeX`ExpressionToTeX] /:
Convert`TeX`ExpressionToTeX[e__] /; !TrueQ@$TeX := Block[
{$TeX = True},
Convert`TeX`ExpressionToTeX[e]
]
Let's take a look at an example:
x+2y //TeXForm
$x+2\times y$
Perfect. For your more complicated example:
(z03*z14*z32 + z01*z12*z43 + z14*(z01 + z03 + z12 + z32)*z43) //TeXForm
$\text{z14}\times \text{z43}\times
(\text{z01}+\text{z03}+\text{z12}+\text{z32})+\text{z01}\times \text{z12}\times
\text{z43}+\text{z03}\times \text{z14}\times \text{z32}$
Here is the above code in one block:
Initial /: Verbatim[TagSetDelayed][Initial[sym_], lhs_, rhs_] := With[
{
new=Block[{sym},
TagSetDelayed[sym,lhs,rhs];
First @ Language`ExtendedDefinition[sym]
],
protect=Unprotect[sym]
},
sym;
Quiet@MakeBoxes[sym[],TraditionalForm];
Unprotect[sym];
Replace[
new,
Rule[values_,n:Except[{}]] :> (
values[sym] = DeleteDuplicates @ Join[n, values[sym]]
),
{2}
];
Protect@protect;
]
Initial[TraditionalForm] /: MakeBoxes[e_, TraditionalForm] /; TrueQ@$TeX := Block[{$TeX = False},
ReplaceAll[
MakeBoxes[e, TraditionalForm],
RowBox[b_?productQ] :> RuleCondition @ Replace[RowBox[b], " "->"\[Times]", {2}]
]
]
productQ[b_] := Length[b]>1 && MatchQ[b[[2 ;; -2 ;; 2]], {" "..}]
Initial[Convert`TeX`ExpressionToTeX] /:
Convert`TeX`ExpressionToTeX[e__] /; !TrueQ@$TeX := Block[
{$TeX = True},
Convert`TeX`ExpressionToTeX[e]
]
\[Times]
instead of*
for multiplication? $\endgroup$