10
$\begingroup$

I use TeXForm to convert output of some computation to Latex. I'd like to ask if there is a way to override/change/customize some of these conversions, related to just the name Mathematica assigns to some special functions in its Latex output, since it is not clear what they are in the Latex after the conversion.

Here is an example. FresnelC function is changed to C in Latex. So someone reading the latex PDF, will not really know what C is and I like to keep the name as FresnelC. I suppose I could add note saying that C is FresnelC, but this is all automated, and I do not know before hand that the solution being generated even has FresnelC in it to make the note. I just look at the final Latex output.

MWE

sol = y[t] /. First@DSolve[y'[t] + y[t] Sqrt[t] Sin[t] == 0, y[t], t]

Mathematica graphics

But the Latex output is

TeXForm[sol]
(*  c_1 e^{\sqrt{t} \cos (t)-\sqrt{\frac{\pi }{2}} 
       C\left(\sqrt{\frac{2}{\pi }} \sqrt{t}\right)} *)

Which is rendered as

$$c_1 e^{\sqrt{t} \cos (t)-\sqrt{\frac{\pi }{2}} C\left(\sqrt{\frac{2}{\pi }} \sqrt{t}\right)}$$

I'd like it to still show as the full name FresnelC

$$c_1 e^{\sqrt{t} \cos (t)-\sqrt{\frac{\pi }{2}} \text{FresnelC}\left(\sqrt{\frac{2}{\pi }} \sqrt{t}\right)}$$

So it is more clear. This is how Maple does it also:

Mathematica graphics

This does not only affect the above function, but others as well. For example

 TeXForm[CosIntegral[x]]

gives

$$\text{Ci}(x)$$ and I'd like to keep the same in the Latex as the name in the Mathematica command.

$$\text{CosIntegral}(x)$$

Since it is more clear.

Question is: Is there a way to customize some of these conversions?

$\endgroup$
14
$\begingroup$

You could use my TeXUtilities package:

Import@"https://raw.githubusercontent.com/jkuczm/MathematicaTeXUtilities/master/NoInstall.m"

Unprotect[FresnelC, CosIntegral];
Format[FresnelC@x_, TeXForm] := TeXVerbatim["\\operatorname{FresnelC}"]@x
Format[CosIntegral@x_, TeXForm] := TeXVerbatim["\\operatorname{CosIntegral}"]@x
(* Move TeXForm format to begining of FormatValues so they take precedence over existing ones. *)
(FormatValues@# = Join[#@False, #@True]&@GroupBy[FormatValues@#, FreeQ@TeXForm]) & /@ {FresnelC, CosIntegral};
Protect[FresnelC, CosIntegral];

Now use TeXForm as usual:

y[t] /. First@DSolve[y'[t] + y[t] Sqrt[t] Sin[t] == 0, y[t], t] // TeXForm
(* c_1 e^{\sqrt{t} \cos (t)-\sqrt{\frac{\pi }{2}} \operatorname{FresnelC}\left(\sqrt{\frac{2}{\pi }} \sqrt{t}\right)} *)

$c_1 e^{\sqrt{t} \cos (t)-\sqrt{\frac{\pi }{2}} \operatorname{FresnelC}\left(\sqrt{\frac{2}{\pi }} \sqrt{t}\right)}$

CosIntegral[x] // TeXForm
(* \operatorname{CosIntegral}(x) *)

$\operatorname{CosIntegral}(x)$

$\endgroup$
  • $\begingroup$ fyi, for some reason, the above no longer works in 11.3. I was going to post question, but thought to check if you also see the same thing. I run the same code above, but the Latex remains as before, and did not get modify as shown above. $\endgroup$ – Nasser Mar 24 '18 at 8:56
  • $\begingroup$ @Nasser Thanks for noticing this. Original answer was using version 1.0.0 of TeXUtilities, which was completely ignoring TraditionalForm format, when converting to TeX, symbols that had any TeXForm formatting set. This was considered a bug, and was fixed in version 1.0.1 of package. Now some extra care needs to be taken to make sure that newly set formatting takes precedence over built-in formatting. I've updated the answer. $\endgroup$ – jkuczm Mar 24 '18 at 22:32
8
$\begingroup$

I will assume that you want the normal TraditionalForm typesetting in a notebook to be unaffected, and only want to see the TeXForm of FresnelC, CosIntegral and other targeted functions changed. Also, I assume you don't want to have to use a new function, like myTeXForm, but would rather just use TeXForm as you usually do.

TeXForm works by first converting an expression into TraditionalForm boxes, and then converting those boxes into a TeX string. So, one possibility is to do as @QuantumDot suggests, and modify the functions that convert the boxes to a TeX string. However, I prefer avoiding the creation of the wrong boxes. Another possibility is to do as @b3m2a1 suggests, but then both the TeXForm and normal TraditionalForm typesetting will be affected.

Instead, I would modify the expression to boxes internal function so that it creates the desired boxes. This can be done by having this function set a global variable, say $TeX, to True. Then, when the expression is converted to boxes, a conditioned FormatValue can be used to create the TraditionalForm boxes you want.

Initial

It will be convenient to make use of the function Initial from my answer to How can one manually change the rule ordering:

Initial /: Verbatim[TagSetDelayed][Initial[sym_], lhs_, rhs_] := With[
    {
    new = Block[{sym},
        TagSetDelayed[sym, lhs, rhs];
        First @ Language`ExtendedDefinition[sym]
    ],
    protect=Unprotect[sym]
    },

    sym;
    Replace[new,
        Rule[values_, n:Except[{}]] :> (values[sym] = Prepend[values[sym],n]),
        {2}
    ];
    Protect@protect;
]

This function creates a new *Value, and prepends it to the existing *Values. It also forces autoloading of any necessary packages (.mx) files that will populate the *Values of the function before the new *Value is added.

Convert`TeX`ExpressionToTeX

The internal function I will modify is Convert`TeX`ExpressionToTeX:

Initial[Convert`TeX`ExpressionToTeX] /: 
    Convert`TeX`ExpressionToTeX[e__] /; !TrueQ@$TeX := Block[
        {$TeX = True},
        Convert`TeX`ExpressionToTeX[e]
    ]

Note that when $TeX is not True, the above DownValue will set $TeX to True, and then use the old DownValue.

FormatValues

The new TraditionalForm FormatValues are:

Initial[FresnelC] /: MakeBoxes[FresnelC[a_], TraditionalForm] /; $TeX :=
    MakeBoxes[Defer[FresnelC][a], TraditionalForm]
Initial[CosIntegral] /: MakeBoxes[CosIntegral[a_], TraditionalForm] /; $TeX :=
    MakeBoxes[Defer[CosIntegral][a], TraditionalForm]

Note the use of the $TeX condition. Also, note the use of Defer[FresnelC] on the RHS so that no recursion errors occur. Finally, I like using Defer[FresnelC] instead of something like HoldForm[FresnelC] because the boxes that are produced are simpler. Compare:

MakeBoxes[Defer[FresnelC], TraditionalForm]
MakeBoxes[HoldForm[FresnelC], TraditionalForm]

"FresnelC"

TagBox["FresnelC", HoldForm]

Results

Here we see the new TeXForm formatting in action:

ToString[{FresnelC[a], CosIntegral[b]}, TeXForm]

"\{\text{FresnelC}(a),\text{CosIntegral}(b)\}"

And here we see the normal TraditionalForm typesetting is still in place:

{FresnelC[a], CosIntegral[b]} //TraditionalForm

{C(a),Ci(b)}

Update

To address the question in the comments, defining:

System`Convert`TeXFormDump`maketex[s_String] /; !StringMatchQ[s, "\""~~___~~"\""] && SyntaxQ[s, TeXForm] := Replace[
    s,
    {
        n_ /; StringMatchQ[n, NumberString] :> n,
        w_?wordQ :> "\\operatorname{"<>w<>"}"
    }
]

wordQ[s_String] := Length @ StringSplit[s, WordBoundary] == 1

should make operators use \operatorname instead of \text.

$\endgroup$
  • 1
    $\begingroup$ In Initial definition you're assigning to global protect symbol. Is that intentional? $\endgroup$ – jkuczm Aug 17 '17 at 11:34
  • $\begingroup$ @jkuczm No, that was just an oversight. Thanks. $\endgroup$ – Carl Woll Aug 17 '17 at 14:53
  • $\begingroup$ Is it possible to make it generate \operatorname{Fresnel} instead of \text{FresnelC}? I tried to change your code but did not know how to. Thanks. $\endgroup$ – Nasser Apr 1 '18 at 1:27
  • $\begingroup$ @Nasser Please see my (answer) to question (47417), specifically the change to the DownValues for the symbol System`Convert`TeXFormDump`maketex. $\endgroup$ – Carl Woll Apr 1 '18 at 20:13
  • 1
    $\begingroup$ hi Carl. I found a bug in the above change to replace \text with \operatorname So I will just keep using text{} for now. Here is an example. result=Integrate[(1-x^4+x^8)^(-1),x] and now using TeXForm on the result, when adding your rules, not all text are converted. so the resulting Latex gives error when compiled. Here is screen shot !Mathematica graphics It might not be worth fixing it. I'll just go back to leaving text as is. Just wanted to let you know. Thanks. $\endgroup$ – Nasser Apr 4 '18 at 1:34
5
$\begingroup$

Another option is to just reset the TraditionalForm format of CosIntegral (or whatever symbol you want to mess with):

Unprotect[CosIntegral];
Format[CosIntegral[b_], TraditionalForm] := 
  RawBoxes@RowBox[{"CosIntegral", "(", MakeBoxes[b, TraditionalForm], 
     ")"}];
FormatValues[CosIntegral] = RotateRight@FormatValues[CosIntegral];
Protect[CosIntegral];
CosIntegral // FormatValues

{HoldPattern[MakeBoxes[CosIntegral[b_], TraditionalForm]] :> \!\(\*
TagBox[
FormBox[
RowBox[{"CosIntegral", "(", "b", ")"}],
TraditionalForm],
Format[#, TraditionalForm]& ]\), 
 HoldPattern[
   MakeBoxes[CosIntegral[BoxForm`a$_], TraditionalForm] /; 
    BoxForm`sufficientVersionQ[6.1]] :> 
  TemplateBox[{MakeBoxes[BoxForm`a$, TraditionalForm]}, 
   "CosIntegral"]}

Then:

CosIntegral[x] // TraditionalForm // ToBoxes // FE`makePlainText
CosIntegral[x] // TeXForm // ToBoxes // FE`makePlainText

"CosIntegral(x)"

"\\text{CosIntegral}(x)"
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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