Repository: sympy/sympy
Pull request: latex : order wise printing of monomials 
Fixes #14316 

#### Brief description of what is fixed or changed
The issue arose because `Poly` was being printed as an Expr instance (`poly.as_expr()`) rather than a Poly.
```
>>> Poly([a, 1, b, 2, c, 3], x).as_expr()
a*x**5 + b*x**3 + c*x + x**4 + 2*x**2 + 3
```
This branch rather prints `Poly` term by term (similar approach is used in `str`).
review @normalhuman 


Problem statement:
LaTeX printer does not use the same order of monomials as pretty and str 
When printing a Poly, the str and pretty printers use the logical order of monomials, from highest to lowest degrees. But latex printer does not. 
```
>>> var('a b c x')
>>> p = Poly([a, 1, b, 2, c, 3], x)
>>> p
Poly(a*x**5 + x**4 + b*x**3 + 2*x**2 + c*x + 3, x, domain='ZZ[a,b,c]')
>>> pretty(p)
"Poly(a*x**5 + x**4 + b*x**3 + 2*x**2 + c*x + 3, x, domain='ZZ[a,b,c]')"
>>> latex(p)
'\\operatorname{Poly}{\\left( a x^{5} + b x^{3} + c x + x^{4} + 2 x^{2} + 3, x, domain=\\mathbb{Z}\\left[a, b, c\\right] \\right)}'
```

Hints from issue discussion:

Commit message: changes in _print_Poly

Patch to review:
diff --git a/sympy/printing/latex.py b/sympy/printing/latex.py
index fa55bfc3d09e..2facf3027561 100644
--- a/sympy/printing/latex.py
+++ b/sympy/printing/latex.py
@@ -1813,7 +1813,50 @@ def _print_PolynomialRingBase(self, expr):
 
     def _print_Poly(self, poly):
         cls = poly.__class__.__name__
-        expr = self._print(poly.as_expr())
+        terms, gens = [], [s for s in poly.gens]
+        for monom, coeff in poly.terms():
+            s_monom = None
+            for i, exp in enumerate(monom):
+                if exp > 0:
+                    if exp == 1:
+                        s_monom = self._print(gens[i])
+                    else:
+                        s_monom = self._print(pow(gens[i], exp))
+
+            if coeff.is_Add:
+                if s_monom:
+                    s_coeff = r"\left(%s\right)" % self._print(coeff)
+                else:
+                    s_coeff = self._print(coeff)
+            else:
+                if s_monom:
+                    if coeff is S.One:
+                        terms.extend(['+', s_monom])
+                        continue
+
+                    if coeff is S.NegativeOne:
+                        terms.extend(['-', s_monom])
+                        continue
+
+                s_coeff = self._print(coeff)
+
+            if not s_monom:
+                s_term = s_coeff
+            else:
+                s_term = s_coeff + " " + s_monom
+
+            if s_term.startswith('-'):
+                terms.extend(['-', s_term[1:]])
+            else:
+                terms.extend(['+', s_term])
+
+        if terms[0] in ['-', '+']:
+            modifier = terms.pop(0)
+
+            if modifier == '-':
+                terms[0] = '-' + terms[0]
+
+        expr = ' '.join(terms)
         gens = list(map(self._print, poly.gens))
         domain = "domain=%s" % self._print(poly.get_domain())
 
diff --git a/sympy/printing/tests/test_latex.py b/sympy/printing/tests/test_latex.py
index 66317c525c1f..084794822e31 100644
--- a/sympy/printing/tests/test_latex.py
+++ b/sympy/printing/tests/test_latex.py
@@ -1132,11 +1132,18 @@ def test_latex_Poly():
     assert latex(Poly(x**2 + 2 * x, x)) == \
         r"\operatorname{Poly}{\left( x^{2} + 2 x, x, domain=\mathbb{Z} \right)}"
     assert latex(Poly(x/y, x)) == \
-        r"\operatorname{Poly}{\left( \frac{x}{y}, x, domain=\mathbb{Z}\left(y\right) \right)}"
+        r"\operatorname{Poly}{\left( \frac{1}{y} x, x, domain=\mathbb{Z}\left(y\right) \right)}"
     assert latex(Poly(2.0*x + y)) == \
         r"\operatorname{Poly}{\left( 2.0 x + 1.0 y, x, y, domain=\mathbb{R} \right)}"
 
 
+def test_latex_Poly_order():
+    assert latex(Poly([a, 1, b, 2, c, 3], x)) == \
+        '\\operatorname{Poly}{\\left( a x^{5} + x^{4} + b x^{3} + 2 x^{2} + c x + 3, x, domain=\\mathbb{Z}\\left[a, b, c\\right] \\right)}'
+    assert latex(Poly([a, 1, b+c, 2, 3], x)) == \
+        '\\operatorname{Poly}{\\left( a x^{4} + x^{3} + \\left(b + c\\right) x^{2} + 2 x + 3, x, domain=\\mathbb{Z}\\left[a, b, c\\right] \\right)}'
+
+
 def test_latex_ComplexRootOf():
     assert latex(rootof(x**5 + x + 3, 0)) == \
         r"\operatorname{CRootOf} {\left(x^{5} + x + 3, 0\right)}"


Code review comments:
diff_hunk: @@ -1813,7 +1813,50 @@ def _print_PolynomialRingBase(self, expr):
 
     def _print_Poly(self, poly):
         cls = poly.__class__.__name__
-        expr = self._print(poly.as_expr())
+        terms, gens = [], [s for s in poly.gens]
+        for monom, coeff in poly.terms():
+            s_monom = None
path: sympy/printing/latex.py
text: @user1:
I think s_monom should start out being an empty string, which will be extended in the loop immediately below.

diff_hunk: @@ -1813,7 +1813,50 @@ def _print_PolynomialRingBase(self, expr):
 
     def _print_Poly(self, poly):
         cls = poly.__class__.__name__
-        expr = self._print(poly.as_expr())
+        terms, gens = [], [s for s in poly.gens]
path: sympy/printing/latex.py
text: @user1:
These would be more readable if on separate lines. 
Also, why `[s for s in poly.gens]` instead of `list(poly.gens)`?
Also, why do this at all? (introduce variable gens, convert poly.gens to a list)?  `poly.gens` is a tuple which will work just fine for your purposes: `gens[i]` becomes `poly.gens[i]`.

@user1:
Also, a variable named `gens`  already appears near the end of the function, where it means something different. Variable names shouldn't be reused like this, it makes the code harder to read.

diff_hunk: @@ -1813,7 +1813,50 @@ def _print_PolynomialRingBase(self, expr):
 
     def _print_Poly(self, poly):
         cls = poly.__class__.__name__
-        expr = self._print(poly.as_expr())
+        terms, gens = [], [s for s in poly.gens]
+        for monom, coeff in poly.terms():
+            s_monom = None
+            for i, exp in enumerate(monom):
+                if exp > 0:
+                    if exp == 1:
+                        s_monom = self._print(gens[i])
path: sympy/printing/latex.py
text: @user1:
This overwrites the previous value of s_monom every time, so only the last of the generators (the variables of the polynomial) survives. For example, 
```
>>> latex(Poly(x**2*y**2 + x*y, (x, y)))
'\\operatorname{Poly}{\\left( y^{2} + y, x, y, domain=\\mathbb{Z} \\right)}'
```
You probably want `s_monom += ...` here. Compare to what str printer does (it prints correctly).

For testing purposes, try something like 
```
latex(Poly(a*x**3 + x**2*y - x*y - c*y**3 - b*x*y**2 + y - a*x + b, (x, y)))
```