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.

Recently, we had a nice question which brought up an issue that I believe is a bug. In the tutorial Defining Output Formats is an example at the end which doesn't make sense

This specifies the TeXForm for the symbol x.

Format[x, TeXForm] := "{\\bf x}"

The output format for x that you specified is now used whenever the TeX form is needed.

TeXForm[1 + x^2] 
(* x^2+1 *)

The given output is wrong and should instead be something like {\bf x}^2+1. Therefore, I tested this with my colleague on all versions available to us and the output below shows, that it only worked back in version 4.2.

Is there a simple reason why Format does not work as advertised?

Version 4.2

Format[x,TeXForm]:="{\\bf x}";
TeXForm[1+x^2]
(* 1 + {{\bf x}}^2 *)

Version 5.1

Format[x,TeXForm]:="{\\bf x}";
TeXForm[1+x^2]
(* x^2+1 *)

Version 6.0

Format[x, TeXForm] := "{\\bf x}";
TeXForm[1 + x^2]
(* x^2+1 *)

Version 7.0

Format[x, TeXForm] := "{\\bf x}";
TeXForm[1 + x^2]
(* x^2+1 *)

Version 8.0

Format[x, TeXForm] := "{\\bf x}";
TeXForm[1 + x^2]
(* x^2+1 *)

Version 9.0

Format[x, TeXForm] := "{\\bf x}";
TeXForm[1 + x^2]
(* x^2+1 *)
share|improve this question
    
From Mathematica's help: Format[s]:=rhs defines a symbol s to print like rhs. –  Gregory Rut May 7 at 9:41
1  
@GregoryRut How does that answer the question? –  Sjoerd C. de Vries May 7 at 10:50
    
Has Format ever worked (reliably) as advertised? Not in my experience. Just use MakeBoxes instead; forget about Format. :) –  Oleksandr R. May 7 at 12:31
1  
@RolfMertig it works with any $BoxForms, which are StandardForm and TraditionalForm. These are called by TeXForm on its argument, and the latter then displays as the $\TeX$ corresponding to the resulting boxes. It isn't the most elegant approach, I admit, but without knowledge of how the TeXForm display is obtained internally (probably the the FE sees it and produces some special boxes?), this hijacking seems to be the best we can do. –  Oleksandr R. May 7 at 13:00
2  
Note: the Format rule is applied in TeXForm[x]. It is possible that a format is applied in TeXForm only when it matches the whole expression. –  Michael E2 May 9 at 12:37

3 Answers 3

If someone is after an easy workaround, then here it is: First, you have to initialise the TeX conversion system by simply calling something like TeXForm[1] when you are working on a fresh Kernel.

After that it is simply

System`Convert`TeXFormDump`maketex["x"] = "{\\bf x}";
TeXForm[x^2 + 1]
(* {\bf x}^2+1 *)

For a detailed explanation, please see here.

Note that this only works around the issue and doesn't explain, why it is not working as described.

share|improve this answer

This is not an answer, but a comment to halirutans answer that is to big for a comment.

It's important to stress that, if we want special TeXForm for an expression, argument given to System`Convert`TeXFormDump`maketex should be low level box representation of that expression in TraditionalForm.

For symbol it's just string with symbols name:

TeXForm[1](* initialise *)

System`Convert`TeXFormDump`maketex["x"] = "\\text{special TeXForm of x}";
TeXForm[1 + x]
(* \text{special TeXForm of x}+1 *)

For complicated expressions we can use MakeBoxes:

System`Convert`TeXFormDump`maketex[MakeBoxes[f[a, b], TraditionalForm]] = "\\f[a]{b}";
TeXForm[1 + f[a, b]]
(* \f[a]{b}+1 *)

But if one wants special TeXForm of any expression matching given pattern, it's more complicated.

System`Convert`TeXFormDump`maketex[MakeBoxes[g[a_], TraditionalForm]] := "\\g{" <> a <> "}"
TeXForm[g[a + 1]]
(* g(a+1) *)

Above does not work because boxes representing an "expression pattern":

MakeBoxes[g[a_], TraditionalForm] // FullForm
(* RowBox[List["g", "(", "a_", ")"]] *)

are something different than "box pattern" matching boxes representing any expression matching said "expression pattern". For simple pattern like the one above it's easy to write appropriate "box pattern" by hand:

System`Convert`TeXFormDump`maketex[RowBox[{"g", "(", a_, ")"}]] :=
    "\\g{" <> System`Convert`TeXFormDump`MakeTeX[a] <> "}"
    (* Note the use of MakeTeX with capital letters on RHS
       it's needed to properly use "BoxRules",
       that can be passed as an option to Convert`TeX`BoxesToTeX *)

TeXForm[g[a + 1]]
(* \g{a+1} *)

but for more complicated patterns it's very cumbersome.

Code samples tested in version 9.0.1.0 on Linux.

share|improve this answer

What Format does

Role of Format, as I understand it, is to set appropriate transformation rules. One can check those rules using FormatValues function:

Format[x, TeXForm] = "{\\bf x}";
FormatValues[x] // FullForm
(* List[RuleDelayed[HoldPattern[Format[x, TeXForm]], "{\\bf x}"]] *)

One can also see those rules by inspecting symbol for which rules where set:

?x
(* Global`x *)
(* x/:Format[x,TeXForm]={\bf x} *)

So Format alone correctly assigns proper transformation rules. It's TeXForm that is not using them as it should.


What TeXForm does

There are two problems with how TeXForm works.

Problem 1: When formatting rules are used, what we have set as RHS of Format is not used verbatim, but converted to $\TeX$.

As it's noted in comment by @MichaelE2, if we pass expression with defined rules directly to TeXForm

TeXForm[x]
(* \text{$\{\backslash \backslash $bf x$\}$} *)

transformation rules are used, but string "{\\bf x}" is converted to $\TeX$.

Problem 2: Formatting rules are not used for subexpressions of expression passed to TeXForm.

TeXForm[1 + x^2]
(* x^2+1 *)

How TeXForm works under the hood is described in answers to question mentioned by OP.

As stated in Properties & Relations section of Format documentation MakeBoxes use formatting rules added by Format. MakeBoxes is used by TeXForm, but as noted in comment by @RolfMertig and explained in comment by @OleksandrR. TeXForm is not one of $BoxForms and internally TeXForm converts expression to boxes in TraditionalForm. So formatting rules for TeXForm are just not used anywhere.


How to work around TeXForm problems

Problem 1

To deal with it we can define a wrapper that, when converted to $\TeX$, will return its content verbatim:

TeXVerbatim::usage = "TeXVerbatim[\"str\"] converted to TeX gives verbatim \"str\"."

Let's use System`Convert`TeXFormDump`maketex to force appropriate $\TeX$ conversion:

System`Convert`TeXFormDump`maketex[
    RowBox[{
        "TeXVerbatim",
        "(" | "[", 
        arg_String?(StringMatchQ[#, "\"" ~~ ___ ~~ "\""] &), 
        ")" | "]"
    }]
] :=
    ToExpression[arg]

This is the only place where we'll use this internal function and only "box pattern" we need to write by hand. Let's check that it works:

TeXVerbatim["\\macro $1+1$ \\command[a=b]{c}"] // TeXForm
(* \macro $1+1$ \command[a=b]{c} *)

Now use it in Format:

Format[x, TeXForm] := TeXVerbatim["{\\bf x}"]
TeXForm[x]
(* {\bf x} *)

Problem 2

First let's define function that applies relevant rules to given expression:

ApplyTeXFormFormat::usage =
    "ApplyTeXFormFormat[expr] returns expr with all subexpressions that \
    have custom TeX formating rules replaced with their TeX form."

ApplyTeXFormFormat[expr_] :=
    expr /.
        Flatten[
            Cases[
                (* Get formating rules, *)
                FormatValues[#]
                ,
                (* take only rules defined for TeXFormat *)
                HoldPattern[HoldPattern[HoldPattern][Format[x_, TeXForm]] :> xTeX_] :>
                    (* and change them to replacement rules for bare transformed expression. *)
                    (HoldPattern[x] :> xTeX)
            ] & /@
                (* Perform above for all symbols found in expr. *)
                DeleteDuplicates[
                    Cases[expr, _Symbol, {0, Infinity}, Heads -> True]]
                ]
        ]

Since those rules transform expression and not low level boxes they could be used anywhere before MakeBoxes is called on expression passed to TeXForm.

We can either define own function that will apply transformation rules and convert expression to $\TeX$:

TeXFormAll::usage =
    "TeXFormAll[expr] prints TeX version of expr with custom formating \
    applied to each subexpression."

TeXFormAll[expr_] := TeXForm[ApplyTeXFormFormat[expr]]

TeXFormAll[1 + x^2]
(* {\bf x}^2+1 *)

or redefine built in Convert`TeX`ExpressionToTeX function so that TeXForm will work as expected:

Unprotect[Convert`TeX`ExpressionToTeX];

Convert`TeX`ExpressionToTeX[expr_, opts___?OptionQ] :=
    Convert`TeX`BoxesToTeX[
        ToBoxes[ApplyTeXFormFormat[expr], TraditionalForm],
        opts,
        "BoxRules" -> System`Convert`TeXFormDump`$GreekWords
     ]

Protect[Convert`TeX`ExpressionToTeX];

TeXForm[1 + x^2]
(* {\bf x}^2+1 *)

Package

I've created a package implementing above concepts together with some additional functions to customize TeX output. It is available on GitHub.

Its example usage could be:

Get["https://raw.githubusercontent.com/jkuczm/MathematicaTeXUtilities/master/TeXUtilities/TeXUtilities.m"]
Get["https://raw.githubusercontent.com/jkuczm/MathematicaTeXUtilities/master/TeXUtilities/FormatTeXFormPatch.m"]


Format[something, TeXForm] = TeXVerbatim["\\macro $1+1$ \\command[a=b]{c}"];

Format[f[x__], TeXForm] := TeXDelimited["\\left(", x, "\\right)", "DelimSeparator" -> ""]

Format[g[x__], TeXForm] := TeXCommand["g", {{a -> b}, x}]

Format[h[x__], TeXForm] := TeXEnvironment["myEnv", x]

h[
    f[1 + alpha],
    5 - g[3, g[2]],
    something
] // TeXForm
(*
\begin{myEnv}
    \left(\alpha +1\right)
    5-\g[a=b]{3}{\g[a=b]{2}}
    \macro $1+1$ \command[a=b]{c}
\end{myEnv}
*)
share|improve this answer

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.