2
$\begingroup$

Note: Afraid I did not initially adequately specify the precise Latex format of the algebraic expression. Edited to make more clear.

I am having problems transferring polynomials in two variables $f(z,w)$ from Mathematica to latex in the form of $$ a_0(z)+a_1(z)w+a_2(z)w^2+\cdots+a_n(z)w^n $$ where $a_i(z)$ are polynomials in z with increasing powers such as $a_1(z)=1+3 z+4 z^4+z^5$.

In the Latex output, would like the terms in $a_i(z)$ to be in parentheses even if just one term like $\left(z^3\right)w^{10}$ or if a negative number like $\left(-1\right)w^{24}$ and with $+$ always between the monomials $a_i(z)w^i$. Also, would like the Latex to be professional-looking; no $w^0$ or $z^0$ or $+-3$ for example, and all fractions in $\frac{a}{b}$ form.

For example the expression:

-((5 w^8)/4) - w^24 - (w^5 z)/4 + (w^25 z^2)/2 - (6 w^20 z^3)/5 + 
  3 w^13 z^4 - (w^28 z^11)/3 - w^40 z^12 + (5 w^29 z^16)/3 + 
  w^23 z^17 - (6 w^32 z^17)/5 - 5 w^38 z^17 + (7 w^39 z^18)/5 - 
  w^4 z^21 + (7 z^25)/3 + w^26 z^26 - 2 w^13 z^27 + (w^20 z^27)/5 - 
  2 w^33 z^27 - 4 w^38 z^28 - (5 w^8 z^33)/4 - (w^26 z^33)/5 - (
  4 w^22 z^36)/3 - (2 w^29 z^37)/5 - (8 w^6 z^39)/5;

should render in Latex in the following form but without the alignment which I just added to make it easier to read.

$$ \begin{align*} &\left(\frac{7}{3}z^{25}\right)+\left(-z^{21}\right)w^4+\left(-\frac{1}{4}z\right)w^5+\left(-\frac{8}{5}z^{39}\right)w^6 \\&+\left(-\frac{5}{4}-\frac{5}{4}z^{33}\right)w^8\\ &+\left(3z^4-2z^{27}\right)w^{13}+\left(-\frac{6}{5}z^3+\frac{1}{5}z^{27}\right)w^{20}+\left(-\frac{4}{3}z^{36}\right)w^{22}+\left(z^{17}\right)w^{23}\\ &+\left(-1\right)w^{24}+\left(\frac{1}{2}z^2\right)w^{25}+\left(z^{26}-\frac{1}{5}z^{33}\right)w^{26}+\left(-\frac{1}{3}z^{11}\right)w^{28}\\ &+\left(\frac{5}{3}z^{16}-\frac{2}{5}z^{37}\right)w^{29}+\left(-\frac{6}{5}z^{17}\right)w^{32}+\left(-2z^{27}\right)w^{33}\\ &+\left(-5z^{17}-4z^{28}\right)w^{38}+\left(\frac{7}{5}z^{18}\right)w^{39}+\left(-z^{12}\right)w^{40} \end{align*} $$

I can write a function to format this expression how I want:

polyForm[poly_, var_] := 
 Module[{coeffs = CoefficientRules[poly, var] // Sort}, 
  Interpretation[
   Row[Table[
     Row[{"(", coeff[[2]], ")", 
       var^coeff[[1, 1]] /. 1 -> ""}], {coeff, coeffs}], "+"], poly]]

polyForm formats it correctly but when I then try to convert it to Latex, the powers of z have been switched.

theVal = polyForm[f, w]
TeXForm@theVal

Can this be modified to maintain the ordering of powers of z?

Edit: I was able to write a messy routine to accomplish this but the bounty is still available to someone that can write a more professional-looking routine.

$\endgroup$
3
  • $\begingroup$ With[{e = polyForm[poly, w]}, TeXForm@HoldForm@e] works for me, at least the TeXForm matches theVal; however, theVal does not have the fractions out in front of the power of z as shown in the TeX example. $\endgroup$
    – Michael E2
    Apr 25, 2022 at 0:33
  • $\begingroup$ @Michael E2: Thanks. But the parentheses aren't sized correctly. Both Carl and Mauricio below have it now. Would you know how I can give them each 100 pts? They really have put in a lot of effort on this. $\endgroup$
    – josh
    Apr 25, 2022 at 11:59
  • $\begingroup$ Award one bounty. Then give a second. Can't have two at one time, though, I think. -- What I meant was that if my version of TeXForm in the comment is wrong, then so it polyForm; however, you indicate that "polyForm formats it correctly." I noticed the parens, too, and thought you didn't care. I can get the fractions out in front, $\frac{7}{3}z^{25}$ instead of $\frac{7z^{25}}{3}$, but only by constructing the boxes. It's a bit of a pain and didn't think it was worth it. The basic idea is simple (well, much like yours), but the darn signs (negatives to become minus unless first). $\endgroup$
    – Michael E2
    Apr 25, 2022 at 13:01

4 Answers 4

4
+100
$\begingroup$

First note that TeXForm use TraditionalForm boxes as a starting point, and TraditionalForm intentionally orders polynomials from higher orders to lower orders. The internal function that does this is TraditionalFormDump`ordplus. Second, note that by default, TraditionalForm chooses the symbol latest in the alphabet as the main variable, and your main variable is w, which comes before z.

The method I will use to fix the ordering issue is to modify the internal symbol Convert`TeX`ExpressionToTeX to block a global variable $TeXto true, and use $TeX conditioned definitions to modify the internal function TraditionalFormDump`ordplus. To fix the main variable issue, I will introduce a wrapper that allows you to decide what the main variable (or rather, the parameter variable) should be. The following code does this:

(* evaluate the symbol to force autoloading *)
Convert`TeX`ExpressionToTeX;

(* modify ExpressionToTeX so that it blocks $TeX to true *)
Unprotect[Convert`TeX`ExpressionToTeX];
Convert`TeX`ExpressionToTeX[expr_, o___?OptionQ] /; !TrueQ@$TeX := Block[{$TeX = True},
    Convert`TeX`ExpressionToTeX[expr, o]
]
Protect[Convert`TeX`ExpressionToTeX];

(* modify ordplus to reverse the order of polynomials *)
TraditionalFormDump`ordplus[x_, y_] /; $TeX := Block[{$TeX=False},
    Reverse @ TraditionalFormDump`ordplus[x,y]
]

(* introduce the wrapper function ParameterVariableForm to allow one to specify what the 
 * parameter variable is, that is, what variables are not the main polynomial variable 
 *)
Options[ParameterVariableForm] = {ParameterVariables -> {}};

ParameterVariableForm /: MakeBoxes[ParameterVariableForm[x_, opts:OptionsPattern[]], TraditionalForm] := 
    MakeBoxes[TraditionalForm[x, opts], TraditionalForm]

And, here is an example:

ParameterVariableForm[
    (w^5/2)+w^4 (1/4-z/2)+w^3 z+z^4+w^2 (1+z^2+z^3)+w (2 z^2+z^4),
    ParameterVariables->{z}
] //TeXForm

$z^4+\left(2 z^2+z^4\right) w+\left(1+z^2+z^3\right) w^2+z w^3+\left(\frac{1}{4}-\frac{z}{2}\right) w^4+\frac{w^5}{2}$

Update

It is possible to enforce parenthesization by using PrecedenceForm. One annoyance is that TraditionalForm will always format something like -a+b as b-a, even if this changes to order of the monomials. So, to avoid this one can use PolynomialForm. Your latest example:

f = -((5 w^8)/4) - w^24 - (w^5 z)/4 + (w^25 z^2)/2 - (6 w^20 z^3)/5 + 
3 w^13 z^4 - (w^28 z^11)/3 - w^40 z^12 + (5 w^29 z^16)/3 + 
w^23 z^17 - (6 w^32 z^17)/5 - 5 w^38 z^17 + (7 w^39 z^18)/5 - 
w^4 z^21 + (7 z^25)/3 + w^26 z^26 - 2 w^13 z^27 + (w^20 z^27)/5 - 
2 w^33 z^27 - 4 w^38 z^28 - (5 w^8 z^33)/4 - (w^26 z^33)/5 - 
(4 w^22 z^36)/3 - (2 w^29 z^37)/5 - (8 w^6 z^39)/5;

This can be converted to TeX per your requirements with:

ParameterVariableForm[
    Collect[f, w, PrecedenceForm[PolynomialForm[#,TraditionalOrder->False],10]&],
    ParameterVariables->{z}
]//TeXForm

$\left(\frac{7 z^{25}}{3}\right)+\left(-z^{21}\right) w^4+\left(-\frac{z}{4}\right) w^5+\left(-\frac{8 z^{39}}{5}\right) w^6+\left(-\frac{5}{4}-\frac{5 z^{33}}{4}\right) w^8+\left(3 z^4-2 z^{27}\right) w^{13}+\left(-\frac{6 z^3}{5}+\frac{z^{27}}{5}\right) w^{20}+\left(-\frac{4 z^{36}}{3}\right) w^{22}+\left(z^{17}\right) w^{23}+(-1) w^{24}+\left(\frac{z^2}{2}\right) w^{25}+\left(z^{26}-\frac{z^{33}}{5}\right) w^{26}+\left(-\frac{z^{11}}{3}\right) w^{28}+\left(\frac{5 z^{16}}{3}-\frac{2 z^{37}}{5}\right) w^{29}+\left(-\frac{6 z^{17}}{5}\right) w^{32}+\left(-2 z^{27}\right) w^{33}+\left(-5 z^{17}-4 z^{28}\right) w^{38}+\left(\frac{7 z^{18}}{5}\right) w^{39}+\left(-z^{12}\right) w^{40}$

Update #2

To have fractions in front in the monomials, you can add the following rule:

Unprotect[Times];
Times /: MakeBoxes[r_Rational s_, TraditionalForm] /; $TeX := RowBox[{
    MakeBoxes[r, TraditionalForm],
    MakeBoxes[s, TraditionalForm]
}]
Protect[Times];

Then:

ParameterVariableForm[
    Collect[f, w, PrecedenceForm[PolynomialForm[#,TraditionalOrder->False],10]&],
    ParameterVariables->{z}
]//TeXForm

$\left(\frac{7}{3}z^{25}\right)+\left(-z^{21}\right) w^4+\left(-\frac{1}{4}z\right) w^5+\left(-\frac{8}{5}z^{39}\right) w^6+\left(-\frac{5}{4}-\frac{5}{4}z^{33}\right) w^8+\left(3 z^4-2 z^{27}\right) w^{13}+\left(-\frac{6}{5}z^3+\frac{1}{5}z^{27}\right) w^{20}+\left(-\frac{4}{3}z^{36}\right) w^{22}+\left(z^{17}\right) w^{23}+(-1) w^{24}+\left(\frac{1}{2}z^2\right) w^{25}+\left(z^{26}-\frac{1}{5}z^{33}\right) w^{26}+\left(-\frac{1}{3}z^{11}\right) w^{28}+\left(\frac{5}{3}z^{16}-\frac{2}{5}z^{37}\right) w^{29}+\left(-\frac{6}{5}z^{17}\right) w^{32}+\left(-2 z^{27}\right) w^{33}+\left(-5 z^{17}-4 z^{28}\right) w^{38}+\left(\frac{7}{5}z^{18}\right) w^{39}+\left(-z^{12}\right) w^{40}$

$\endgroup$
14
  • $\begingroup$ @ Carl Wolf: Unfortunately your code does not work when the monomials in f are mixed (which is what I work with) such as: f = w^2 z^8 - w z^10 + w^2 z^10 + w z^11 - 2 w^2 z^11 + w^3 z^11 + z^12/4 - w z^12 + (3 w^2 z^12)/2 - w^3 z^12 + (w^4 z^12)/4 - z^13/ 2 + 2 w z^13 - 3 w^2 z^13 + 2 w^3 z^13 - (w^4 z^13)/2 + z^14/2 - ( 5 w z^14)/2 + 5 w^2 z^14 - 5 w^3 z^14 + (5 w^4 z^14)/2 - ( w^5 z^14)/2; $\endgroup$
    – josh
    Apr 22, 2022 at 8:03
  • $\begingroup$ @josh Don't you just need to include Collect[f, w]? $\endgroup$
    – Carl Woll
    Apr 22, 2022 at 15:24
  • $\begingroup$ Ok sorry. ParameterValueForm[Collect[f,w] . . .] works. It would be perfect however if the $a_0(z)$ terms were in parentheses as NOva's code as well as my messy code produces. I'll update my post above with my code and will post 100 point bounty later. $\endgroup$
    – josh
    Apr 22, 2022 at 16:26
  • $\begingroup$ @josh You could do: ParameterVariableForm[Collect[f, w, Defer], w]. $\endgroup$
    – Carl Woll
    Apr 22, 2022 at 16:57
  • $\begingroup$ Thanks. Much nicer. However,` ParameterVariableForm[Collect[f, w, Defer]` includes "ParameterVariableForm" in the Latex but if I split it up as theF = Collect[f, w, Defer]; ParameterVariableForm[theF, ParameterVariables -> {z}] // TeXForm that works nicely. $\endgroup$
    – josh
    Apr 22, 2022 at 17:12
3
$\begingroup$

As soon as one lets Mathematica use Plus and Times all custom ordering goes out of the window since it always orders the arguments of Plus and Times according to its internal canonical sorting. The functions are inherently Orderless (a Mathematica function attribute which leads to canonical ordering of function arguments). One can not allow the use of Plus for the sum of terms and products of $(\ldots)w$. I modified the code given in the question for polyForm to have a custom StandartForm and TeXForm (using TeXVerbatim of the TeXUtilities package for the latter).

Needs["TeXUtilities`"] (* https://github.com/jkuczm/MathematicaTeXUtilities *)
ClearAll[polyForm,polyForm`format]

polyForm`format[coeffs_List,var_]:=Row[Row[{If[Head[#[[2]]]===Plus,DisplayForm@RowBox[{"(",#[[2]],")"}],DisplayForm@RowBox[{#[[2]],"\[ThinSpace]"}]],If[#[[1,1]]=!=0,var^#[[1,1]],Nothing]}]&/@coeffs,"+"]

polyForm/:Format[polyForm[coeffs_List,var_],TeXForm]:=TeXVerbatim[StringReplace[ToString@TeXForm[polyForm`format[coeffs,var]],{"+-"->"-","\, +"->"+"}]]
polyForm/:MakeBoxes[polyForm[coeffs_List,var_],StandardForm]/;BoxForm`UseIcons:=With[
    {box=ToBoxes@polyForm`format[coeffs,var]},
    InterpretationBox[box,polyForm[coeffs,var]]
]

polyForm[poly_,var_]:=polyForm[CoefficientRules[poly,var]//Sort,var]/;(!ListQ[poly])


f = -(w^5/2) + w^4 (1/4 - z/2) + w^3 z + z^4 + w^2 (1 + z^2 + z^3) + w (2 z^2 + z^4)
polyForm[f,w]//StandardForm
%//TeXForm (*-> z^4+\left(z^4+2 z^2\right)w+\left(z^3+z^2+1\right)w^2+z\, w^3+\left(\frac{1}{4}-\frac{z}{2}\right)w^4-\frac{1}{2}\, w^5*)

resulting in

Result

which renders in TeX as $$z^4+\left(z^4+2 z^2\right)w+\left(z^3+z^2+1\right)w^2+z\, w^3+\left(\frac{1}{4}-\frac{z}{2}\right)w^4-\frac{1}{2}\, w^5$$

Some of the employed tweaks/replacements for the TeXForm might not be very robust/need to be extended.

$\endgroup$
6
  • $\begingroup$ @NOva: Nice job! The order is important in some work I'm doing. I've tried your code with more complex functions I'm using and it works well. I was planning to post a bounty on it in a bit. It's yours if no one beats your solution. $\endgroup$
    – josh
    Apr 21, 2022 at 21:26
  • $\begingroup$ @josh Did you want the z-polynomials to be ordered from higher orders to lower orders or vice versa? $\endgroup$
    – Carl Woll
    Apr 21, 2022 at 22:35
  • $\begingroup$ @Carl Wolf: Need z-polynomials ordered from low to high powers. If I use NOva's code and write pForm = polyForm[f, w] // StandardForm; pForm // TeXForm then this constructs the Latex code from low to high powers. Not sure why the %//TeXForm above does not do this. $\endgroup$
    – josh
    Apr 22, 2022 at 7:48
  • $\begingroup$ @josh Does f = BesselJ[n, 2] w + w^2 work properly with this approach (I think it won't)? $\endgroup$
    – Carl Woll
    Apr 22, 2022 at 15:26
  • $\begingroup$ @Carl Woll: Just need it to work with pure bivariate polynomials f(z,w). $\endgroup$
    – josh
    Apr 22, 2022 at 16:27
3
$\begingroup$

Here's my fourth attempt over the last couple of days (three of them were successful and one pissed me off). As others have made steps closer to the solution, I'd get discouraged and set it aside: Eh, it's solved or nearly solved....

Then looking at CoefficientList[poly, {w, z}] or even CoefficientRules[poly, {w, z}], you think, gosh, what to do is obvious, let's try again. But Mathematica's choices about fractions and standard conventions about signs in representing addition and numbers make doing something obvious a bit of a pain. @CarlWoll gets close [it] in an elegant way (fractions not in front but otherwise brilliant--now there's a fractions-in-front option); @MauriciodeOliveira gets the formatting perfect, but it doesn't seem elegant to me. Just to be clear, I don't think my solution is all that elegant, either. However, whereas @MauriciodeOliveira aims at the right TeXForm, mine gets the right box form that produces the right TeXForm. The box form has some minor advantages, such as you can copy and paste it as input; or as @CarlWoll suggests in a comment, the code can be packaged into a wrapper that both formats output and works with TeXForm. It's because of this distinction I feel this method adds something to the other answers, and therefore it is worth sharing.

As for elegance, because it's the fourth attempt, it is about half as long as it used to be. :) But you still have to do something about the coefficient 1, sums with one term, and - as a unary/binary op. Luckily, CoefficientRules takes care of all the zero coefficients/terms.

(* helper functions *)
ClearAll[cRules, toPowerBoxes, parenthesizeRow,
 coeffToBoxes, toMonomialBoxes];
cRules[t_][poly_] := Association@Sort@CoefficientRules[poly, {t}];
toPowerBoxes[t_] := KeyMap[MakeBoxes[#] &[t^#] &@*First];
parenthesizeRow[boxes : {b : Except[_List]}] := RowBox[{"(", b, ")"}]; 
parenthesizeRow[boxes_] := 
 RowBox[{"(", RowBox@Flatten@boxes, ")"}];
(* first coeff is treated different *)
coeffToBoxes[assoc_] := MapAt[MakeBoxes, 1]@
   MapAt[{If[Negative[#], "-", "+"], MakeBoxes[#] &@Abs@#} &, 2 ;;]@
    assoc;
(* ±1 are specials cases; no zero coeffs *)
toMonomialBoxes["1", coeff_] := coeff;
toMonomialBoxes[power_, {sign_, coeff_}] :=
  {sign, RowBox[{coeff," ",power}]};
toMonomialBoxes[power_, "1"] := power;
toMonomialBoxes[power_, RowBox[{"-", "1"}]] := RowBox[{"-", power}];
toMonomialBoxes[power_, coeff_] := RowBox[{coeff, " ", power}];

Example:

RawBoxes@
   RowBox@
    Riffle[#, "+"] &@
 KeyValueMap[toMonomialBoxes]@
  Map[parenthesizeRow]@
   Map[
     KeyValueMap[toMonomialBoxes]@*
      coeffToBoxes@*
      toPowerBoxes[z]@*
      cRules[z]
     ]@
    toPowerBoxes[w]@cRules[w][poly]

% // TeXForm

$\displaystyle \left(\frac{7}{3} z^{25}\right)+\left(-z^{21}\right) w^4+\left(-\frac{1}{4} z\right) w^5+\left(-\frac{8}{5} z^{39}\right) w^6+\left(-\frac{5}{4}-\frac{5}{4} z^{33}\right) w^8+\left(3 z^4-2 z^{27}\right) w^{13}+\left(-\frac{6}{5} z^3+\frac{1}{5} z^{27}\right) w^{20}+\left(-\frac{4}{3} z^{36}\right) w^{22}+\left(z^{17}\right) w^{23}+(-1) w^{24}+\left(\frac{1}{2} z^2\right) w^{25}+\left(z^{26}-\frac{1}{5} z^{33}\right) w^{26}+\left(-\frac{1}{3} z^{11}\right) w^{28}+\left(\frac{5}{3} z^{16}-\frac{2}{5} z^{37}\right) w^{29}+\left(-\frac{6}{5} z^{17}\right) w^{32}+\left(-2 z^{27}\right) w^{33}+\left(-5 z^{17}-4 z^{28}\right) w^{38}+\left(\frac{7}{5} z^{18}\right) w^{39}+\left(-z^{12}\right) w^{40}$

Dataset approach:

ds = Dataset@
   Map[toPowerBoxes[z]@*cRules[z]]@
    toPowerBoxes[w]@cRules[w][poly];
ds[All, coeffToBoxes /*
         KeyValueMap[toMonomialBoxes] /*
         parenthesizeRow][
   KeyValueMap[toMonomialBoxes]
   ] // Normal // Riffle[#, "+"] & // RowBox // RawBoxes

or

plusBox[b_] := RowBox@Riffle[b, "+"];
ds[Map[coeffToBoxes /*
        KeyValueMap[toMonomialBoxes] /*
        parenthesizeRow
       ] /*
    KeyValueMap[toMonomialBoxes] /*
    plusBox
   ] // RawBoxes
$\endgroup$
4
  • 1
    $\begingroup$ You could create a wrapper with me /: MakeBoxes[me[p_, {z_, w_}], TraditionalForm] := With[{ds = Dataset@ Map[toPowerBoxes[z]@*cRules[z]]@toPowerBoxes[w]@cRules[w][p]}, ds[All, coeffToBoxes/*KeyValueMap[toMonomialBoxes]/*parenthesizeRow][ KeyValueMap[toMonomialBoxes]] // Normal // Riffle[#, "+"] & // RowBox ] so that me[poly, {z, w}] //TeXForm can be used. $\endgroup$
    – Carl Woll
    Apr 25, 2022 at 17:18
  • $\begingroup$ @Michael: That's very concise and definitely sophisticated and doesn't require loading a custom package asMauriciodeOliveira's solution. Carl, Mauricio, and yours are excellent solutions to this problem. $\endgroup$
    – josh
    Apr 25, 2022 at 18:09
  • $\begingroup$ @Michael E2, was not able to set up multiple bounties on this problem. Would have awarded you, Carl and Mauricio for your help. $\endgroup$
    – josh
    Apr 27, 2022 at 9:32
  • $\begingroup$ @josh No problem. Thanks anyway :) $\endgroup$
    – Michael E2
    Apr 27, 2022 at 13:35
2
$\begingroup$

Original Answer

Since you are not asking for efficiency, I find it more productive to deconstruct the polynomial and use HoldForm instead of boxes to handle the ordering. From there, the standard TeXForm does the job well. The tricky part is to hold the Plus inside the HoldForm. Another aspect that I find important is the handling of negative signs inside parenthesis, as one would not like to have y + y x - x print as y + (-1 + y) x but rather as y - (1 - y) x.

The code needs three auxiliary functions: GetSign, to obtain the sign of an expression, HoldTerms, to perform the multiplication of two terms holding its ordering and hiding possible 1s, and PolyForm, which does the bulk of the job by reconstructing the polynomial using HoldForm to preserve the desired ordering. Here they are:

GetSign[a_?NumberQ] := If[a < 0, -1, 1];
GetSign[a_Times | a_Plus] := GetSign[a[[1]]];
GetSign[a_] = 1;

HoldTerms[coeff_, mon_] := If[coeff === 1, mon, If[mon === 1, coeff, HoldForm[Times[coeff, mon]]]];

PolyForm[p_, x_Symbol, formatCoefficient_ : Identity] := Module[
  {coeff, sign, mon},
  (* get polynomial coefficients *)
  coeff = CoefficientList[Collect[p, x], x];
  (* calculate corresponding monomial and remove zero coefficients *)
  {coeff, mon} = Transpose[
    DeleteCases[
      Transpose[{coeff, Table[x^i, {i, 0, Length[coeff] - 1}]}], 
      _?(PossibleZeroQ[#[[1]]] &)]
  ];
  (* factor sign of coefficients out *)
  sign = GetSign /@ coeff;
  coeff *= sign;
  (* format coefficients *)
  coeff = formatCoefficient /@ coeff;
  (* multiply by monomials and hold, then multiply by sign *)
  coeff = sign*MapThread[HoldTerms, {coeff, mon}];
  (* return *)
  Return[If[
    Length[coeff] > 1,
    (* Apply Plus inside hold and return *)
    With[{z = coeff}, HoldForm[z]] /. List -> Plus,
    (* first entry if list of one *)
    coeff[[1]]
  ]];
];

From these, PolyToTeX basically applies TeXForm to the result of PolyForm. In the case of multiple variables it uses PolyForm to format the coefficients first. This can be extended to more than 2 variables if wanted.

PolyToTeX[p_, x_Symbol] := TeXForm[PolyForm[p, x]];
PolyToTeX[p_, x_Symbol, y_Symbol] := TeXForm[PolyForm[p, x, PolyForm[#, y] &]];

Some examples.

PolyToTeX[y + y x - x, x]  (* factors negative sign *)

y-(1-y) x

PolyToTeX[y + y x - x, y]  (* keeps ordering in the sum *)

-x+(1+x) y

PolyToTeX[y + y x/2 - x, x]  (* uses \frac and factor negative sign *)

y-\left(1-\frac{y}{2}\right) x

or

$y-\left(1-\frac{y}{2}\right) x$

PolyToTeX[y + y^2  z x - x + y x - y^2 x, x, y]  (* format coefficients as poly in y *)

y-\left(1-y+(1-z) y^2\right) x

or

$y-\left(1-y+(1-z) y^2\right) x$

p = (w^5/2) + w^4 (-1/4 + z/2) + w^3 z + z^4 + w^2 (1 + z^2 + z^3) + w (2 z^2 + z^4);
PolyToTeX[p, w]  (* the test polynomial with a flipped minus sign *)

z^4+\left(2 z^2+z^4\right) w+\left(1+z^2+z^3\right) w^2+z w^3-\left(\frac{1}{4}-\frac{z}{2}\right) w^4+\frac{w^5}{2}

or

$z^4+\left(2 z^2+z^4\right) w+\left(1+z^2+z^3\right) w^2+z w^3-\left(\frac{1}{4}-\frac{z}{2}\right) w^4+\frac{w^5}{2}$

Look at

InputForm[PolyForm[p, w]]

to see how PolyForm works

HoldForm[z^4 + HoldForm[(2*z^2 + z^4)*w] + HoldForm[(1 + z^2 + z^3)w^2] + HoldForm[zw^3] - HoldForm[(1/4 - z/2)*w^4] + HoldForm[w^5/2]]

Modified Answer

The requirements added on the comments change the code significantly, hence a new section. The main difficulty is that the rules for the formatting the coefficients are different than the rules for formatting the polynomial, which requires handling different options in each case. Moreover, the requirement for forcing parentheses is also not handled natively by TeXForm, but is handled nicely by the package TexUtilities, which is now a dependence.

Needs["TeXUtilities`"] (* https://github.com/jkuczm/MathematicaTeXUtilities *)

The updated auxiliary functions are:

GetSign[a_?NumberQ] := If[a < 0, -1, 1];
GetSign[a_Times | a_Plus] := GetSign[a[[1]]];
GetSign[a_] = 1;

HoldTerms[1, mon_, sign_ : 1] := sign*mon;
HoldTerms[coeff_, 1, sign_ : 1] := sign*coeff;
HoldTerms[coeff_Rational, mon_, sign_ : 1] := 
  sign*HoldForm[Times[HoldForm[coeff], mon]];
HoldTerms[coeff_, mon_, sign_ : 1] := 
  Times[sign, HoldForm[Times[coeff, mon]]];

Format[ParenthesizeTeX[x__], TeXForm] := 
  TeXDelimited["\\left(", x, "\\right)", "DelimSeparator" -> ""];
ParenthesizeTeXOptional[
  a_Plus | a_Symbol | 
  a : (Power[_, _Integer]) | a_?(NumberQ[#] && Positive[#] &)] := 
  a;
ParenthesizeTeXOptional[a_] := ParenthesizeTeX[a];

Options[PolyForm] = {
  FactorSign -> False,
  ParenthesizeAll -> True,
  FormatCoefficient -> Identity
};
PolyForm[p_, x_Symbol, opts : OptionsPattern[PolyForm]] := Module[
  {coeff, sign, mon},
  (* get polynomial coefficients *)
  coeff = CoefficientList[Collect[p, x], x];
  (* calculate corresponding monomial and remove zero coefficients *)
  {coeff, mon} = 
    Transpose[
      DeleteCases[
        Transpose[{coeff, 
                   Table[x^i, {i, 0, Length[coeff] - 1}]}],
        _?(PossibleZeroQ[#[[1]]] &)]];
  (* factor sign of coefficients out *)

  If[OptionValue[FactorSign] === True,
    sign = GetSign /@ coeff;
    coeff *= sign;
  ];
  (* format coefficients *)
  coeff = OptionValue[FormatCoefficient] /@ coeff;
  (* wrap all terms in parenthesis *)
  coeff = If[OptionValue[ParenthesizeAll],
    ParenthesizeTeX /@ coeff
   ,
    ParenthesizeTeXOptional /@ coeff
  ];
  (* multiply by monomials and hold *)
  coeff = If[OptionValue[FactorSign] === True,
    (* first term might still factor *)
    Prepend[MapThread[HoldTerms, Rest /@ {coeff, mon, sign}], 
            HoldTerms[sign[[1]]*coeff[[1]], mon[[1]]]]
   ,
    MapThread[HoldTerms, {coeff, mon}]
  ];
  Return[If[Length[coeff] > 1,
    (* Apply Plus inside hold and return *)
    With[{z = coeff}, HoldForm[z]] /. List -> Plus
   ,
    (* first entry if list of one *)
    coeff[[1]]]
  ];
];
PolyForm[p_, {x_Symbol}, opts : OptionsPattern[PolyForm]] :=
  PolyForm[p, x, opts];
PolyForm[p_, {x_Symbol, y__Symbol}, opts : OptionsPattern[PolyForm]] :=
  PolyForm[p, x, 
    FormatCoefficient -> (PolyForm[#, {y}, FactorSign -> True, 
    ParenthesizeAll -> False, opts] &), opts];

The drivers are also different in order to interfere with the options.

PolyToTeX[p_, x_Symbol, opts___ : OptionsPattern[PolyForm]] := 
  TeXForm[PolyForm[p, x, opts]];
PolyToTeX[p_, {x__Symbol}, opts___ : OptionsPattern[PolyForm]] := 
  TeXForm[PolyForm[p, {x}, opts]];

For the first example in the comments:

p = (-1/2 + 3 z + 4/5 z^3) + (-3/5 z^4) w^3 + 1/5 w^4;
PolyToTeX[p, {w, z}] 

produce

\left(-\frac{1}{2}+3 z+\frac{4}{5} z^3\right)+\left(-\frac{3}{5} z^4\right) w^3+\left(\frac{1}{5}\right) w^4

or

$\left(-\frac{1}{2}+3 z+\frac{4}{5} z^3\right)+\left(-\frac{3}{5} z^4\right) w^3+\left(\frac{1}{5}\right) w^4$

For the second example in the comments:

p = 1 + (1 - z + 3/5 z^4 + z^5) w - w^2 - z^3 w^5 + (-2/3 z^3 +
  z^5) w^6
PolyToTeX[p, {w, z}] 

produce

\left(1\right)+\left(1-z+\frac{3}{5} z^4+z^5\right) w+\left(-1\right) w^2+\left(-z^3\right) w^5+\left(-\frac{2}{3} z^3+z^5\right) w^6

or

$\left(1\right)+\left(1-z+\frac{3}{5} z^4+z^5\right) w+\left(-1\right) w^2+\left(-z^3\right) w^5+\left(-\frac{2}{3} z^3+z^5\right) w^6$

One can also use options to obtain other formats. For example:

PolyToTeX[p, {w, z}, FactorSign->True, ParenthesizeAll->False] 

produces

1+\left(1-z+\frac{3}{5} z^4+z^5\right) w-w^2-z^3 w^5-\left(\frac{2}{3} z^3-z^5\right) w^6

or

$1+\left(1-z+\frac{3}{5} z^4+z^5\right) w-w^2-z^3 w^5-\left(\frac{2}{3} z^3-z^5\right) w^6$

which is similar to the format of the original answer.

The new code should also works for more than two variables, as in:

p = (-1/2 + (x^2 + 1/2) 3 z + x 4/5 z^3) + (-3/5 z^4 - x) w^3 + 1/5 w^4;
PolyToTeX[p, {w, z, x}]

which produces

\left(-\frac{1}{2}+\left(\frac{3}{2}+3 x^2\right) z+\left(\frac{4}{5} x\right) z^3\right)+\left(-x-\frac{3}{5} z^4\right) w^3+\left(\frac{1}{5}\right) w^4

or

$\left(-\frac{1}{2}+\left(\frac{3}{2}+3 x^2\right) z+\left(\frac{4}{5} x\right) z^3\right)+\left(-x-\frac{3}{5} z^4\right) w^3+\left(\frac{1}{5}\right) w^4$

I haven't tested it enough though.

$\endgroup$
7
  • $\begingroup$ I don't want the flipped negative sign and I want the terms in $a_i(z)$ to be in parentheses if more than one term or if a single term is negative. Also, the rationals in your code seems to be separating into a numerator and 1/denominator. I need the form : $$a_0(z)+a_1(z)w+a_2(z)w^2+\cdots+a_n(z)w^n$$. For ex, $$\left(-\frac{1}{2}+3 z+\frac{4}{5} z^3\right)+\left(-\frac{3}{5}z^4\right)w^3+\frac{1}{5} w^4$$ and so forth. Sorry if that wasn't clear in my post above. $\endgroup$
    – josh
    Apr 24, 2022 at 15:49
  • $\begingroup$ Your choice of not factoring the minus sign is still ambiguous. Do you want 1-x/5 to display as $1+\left(- \frac{1}{5} \right ) x$ (as your example suggests), $1+\left(\frac{-1}{5} \right ) x$, or $1-\frac{1}{5} x$? For this reason, factoring the minus signs seems to me to be the best option. Same goes without fractions: 1-2x should display as $1+(-2) x$? $\endgroup$ Apr 24, 2022 at 18:22
  • $\begingroup$ Another question regarding the parenthesis on the constant term. Should PolyToTeX[x - y,x] display as $(-y) + x$? This is also why I did not think that was a good choice. $\endgroup$ Apr 24, 2022 at 19:00
  • $\begingroup$ In term of $a_0(z)+a_1(z)w+a_2(z)w^2+\cdots+a_n(z)w^n$, would like all $a_i(z)$ in parentheses with a $+$ between each $a_i(z)w^i$ although ok to not include parentheses for $k$ in the case of $a_i(z)=k$ with k a number but would like $\left(-k\right)$ in case $a_i(z)=-k$. As an extreme case: $$\left(1\right)+\left(1-z+\frac{3}{5}z^4 +z^5\right)w+\left(-1\right)w^2+\left(-z^3\right)w^5+\left(-\frac{2}{3}z^3+z^5\right)w^6$$ $\endgroup$
    – josh
    Apr 24, 2022 at 19:44
  • $\begingroup$ Added a new version to address your formatting requirements. $\endgroup$ Apr 24, 2022 at 23:38

Your Answer

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

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