6

How can I reorder the factors in the terms of a polynomial? Consider

poly1 = \!\(\*SubsuperscriptBox[\(x\), \(1\), \(3\)] + \*SubsuperscriptBox[\(x\), \(2\), \(3\)] + \*SubsuperscriptBox[\(x\), \(3\), \(3\)]\  - \ \(TraditionalForm\`\*SuperscriptBox[SubscriptBox[\(σ\), \(1\)], \(3\)]\)\) /.    Subscript[σ,     1] -> (Subscript[x, 1] + Subscript[x, 2] + Subscript[x, 3]) //   Expand

$$\begin{align*}-3 x_2 x_1^2-3 x_3 x_1^2-3 x_2^2 x_1-3 x_3^2 x_1-6 x_2 x_3 x_1-3 x_2 x_3^2-3 x_2^2 x_3\tag{1}\end{align*}$$

MonomialList[poly1, {Subscript[x, 1], Subscript[x, 2], Subscript[x,   3]}, "Lexicographic"]

$$\begin{align*}\left\{-3 x_1^2 x_2,-3 x_1^2 x_3,-3 x_1 x_2^2,-6 x_1 x_2 x_3,-3 x_1 x_3^2,-3 x_2^2 x_3,-3 x_2 x_3^2\right\}\tag{2}\end{align*}$$

% /. List -> Plus

$$\begin{align*}-3 x_2 x_1^2-3 x_3 x_1^2-3 x_2^2 x_1-3 x_3^2 x_1-6 x_2 x_3 x_1-3 x_2 x_3^2-3 x_2^2 x_3\tag{3}\end{align*}$$

Question1: How can I get

$$\begin{align*}-3 x_1^2 x_2-3 x_1^2 x_3-3 x_1 x_2^2-6 x_1 x_2 x_3-3 x_1 x_3^2-3 x_2^2 x_3-3 x_2 x_3^2\tag{4}\end{align*}$$

Question2: Even better if possible, how can I get

$$\begin{align*}-3\left( x_1^2 x_2+x_2^2x_1+\text{...}\right)-6 x_1 x_2 x_3\tag{5}\end{align*}$$

My goal is to keep the order of the terms in (2) unchanged when I copy (4)/(5) into an inline formula cell.

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
HyperGroups
  • 8,619
  • 1
  • 26
  • 63

3 Answers3

5

Question 1

As I said in a comment,

Row@MonomialList[poly1,
      {Subscript[x, 1], Subscript[x, 2], Subscript[x, 3]}, "Lexicographic"]

However, it works easily here because all the coefficients are negative. The following polyForm handles level 1 terms (ignores nesting). It formats the polynomial f with the monomials in a specified order. It will expand a polynomial f (via MonomialList), unless an explicit list of terms is given. It takes the same arguments as MonomialList in the case where the polynomial is passed. If the terms are passed directly in a list, they will be formatted in the same order as they occur in the list.

polyForm[f_Plus, vars_: Automatic, order_: "Lexicographic"] := 
  polyForm[MonomialList[f, vars /. Automatic :> Variables[f], order]];
polyForm[terms_List] := Module[{signs},
   signs = 
    First[Cases[#, c_?NumericQ :> Sign[c]] /. {} -> {1}] & /@ 
     Rest@terms;
   PrecedenceForm[Row[Riffle[{1}~Join~signs terms,
      signs /. {1 -> "\[MediumSpace]+\[MediumSpace]", -1 -> 
         "\[MediumSpace]-\[MediumSpace]"}]], 10]
   ];

polyForm[x_, ___] := x; (* leave other stuff alone *)

Question 2

In this case you can gather the terms by the number of variables each contains:

Total[Factor /@ Plus @@@ GatherBy[List @@ poly1, Length@Variables[#] &]]

Mathematica graphics

Or you can use Row to keep them in the desired order (as in the question):

Row[Factor /@ Plus @@@ GatherBy[List @@ poly1, Length@Variables[#] &]]

Mathematica graphics

Or use polyForm, which will yield the standard spacing around the last minus sign:

polyForm[Factor /@ Plus @@@ GatherBy[List @@ poly1, Length@Variables[#] &]]

Mathematica graphics


Mr.Wizard pointed out that my order is not the same as the desired order in the OP, something I overlooked. Here is a fix:

Factor /@ Plus @@@ GatherBy[MonomialList[poly1, Variables[poly1], "Lexicographic"], 
     Length@Variables[#] &] /. poly_Plus :> polyForm[poly] // polyForm

Here is another:

MapAll[# /. poly_Plus :> polyForm[poly] &, 
 Total[Factor /@ Plus @@@ GatherBy[MonomialList[poly1, Variables[poly1], "Lexicographic"], 
     Length @ Variables[#] &]]]

Mathematica graphics

For the curious, I'll share the following. Using ReplaceAll with poly_Plus :> polyForm[poly] does not work on the Total in the preceding example because is it applies the replacement at the top level first and polyForm expands the polynomial. Here is a way around that, but it does reverse the order at the top level:

Total[Factor /@ Plus @@@ 
    GatherBy[MonomialList[poly1, Variables[poly1], "Lexicographic"], 
     Length@Variables[#] &]] /. Plus -> (polyForm[List[##]] &)
Michael E2
  • 235,386
  • 17
  • 334
  • 747
  • Michael, I don't think this is quite right yet; for example, shouldn't the term −3 x1 x3^3 be the third from the right, not the second as shown above? – Mr.Wizard Aug 11 '13 at 07:45
  • @Mr.Wizard Oops, that's right (assuming you mean -3 x1 x3^2) - I blithely thought the point was just to separate the kinds of terms. – Michael E2 Aug 11 '13 at 11:37
  • Oops.. yes, that's what I meant. – Mr.Wizard Aug 11 '13 at 11:38
  • polyForm[...]//TeXForm complains withTeXForm::unspt: TeXForm of TemplateSlotSequence[1,] is not supported.. Is it possible to change polyForm so that the output can be given to TeXForm? – Hotschke Aug 10 '19 at 15:34
  • @Hotschke This works on the OP's example: RowBox@First@MakeBoxes[#, StandardForm] &@ First@polyForm[ Factor /@ Plus @@@ GatherBy[List @@ poly1, Length@Variables[#] &]] /. "\"\[MediumSpace]-\[MediumSpace]\"" -> "-" // RawBoxes // TeXForm -- Might also need the substitution "\[MediumSpace]+\[MediumSpace]" -> "+", but it doesn't come up in this case. – Michael E2 Aug 10 '19 at 16:32
  • Actually, I think if the \[MediumSpace] instances are deleted from the def. of polyForm, no substitution rules are needed. – Michael E2 Aug 10 '19 at 17:00
3

Related questions:

As shown in answer to the third question above you could use:

HoldForm[+##] & @@ MonomialList[poly1]

enter image description here

(+## is shorthand for Plus[##])

As already noted above and in that answer Row is not sufficient as it will not handle the signs of terms correctly.

For the second question I am borrowing part of Michael's answer, but my result is different and I believe correct:

format = HoldForm[+##] & @@ MonomialList@ # &;

Factor /@ Plus @@@ GatherBy[List @@ poly1, Length@Variables[#] &];

Plus @@ MapAt[format, %, {1, 2}]

enter image description here

The order of these terms appears to match your requested output whereas Michael's output does not.

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
1

This can easily be done by straight manipulation with the Presentations Application, which I sell.

<< Presentations` 

step1 = poly1 // MapLevelParts[FactorOut[-3], {{1, 2, 3, 5, 6, 7}}] 
step2 = MapAt[HoldOrderForm[{1, 3, 2, 5, 4, 6}], step1, {{2, 2}}]

enter image description here enter image description here

FactorOut will factor an arbitrary expression out of an existing expression - even if it is not initially in the expression. MapLevelParts will map a function to a set of level parts in an expression (usually a sum or product or sometimes a list). It applies as a whole to the sub sum, product or list. In your example the level parts are at level 1 but it is also possible to specify a set of level parts at a deeper position.

David Park
  • 2,613
  • 18
  • 14
  • This also doesn't seem to match the requested order. Compare your result to mine. – Mr.Wizard Aug 11 '13 at 08:44
  • @ Mr. Wizard. Well that is easy to fix with another Presentations routine, HoldOrderForm, which allows the permutation of terms or factors. However, the first form does have the advantage of being a normal non-held Mathematica expression. – David Park Aug 11 '13 at 16:28