Repository: sympy/sympy
Pull request: Added relational operator printer for various languages
<!-- Your title above should be a short description of what
was changed. Do not include the issue number in the title. -->

#### References to other Issues or PRs
<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact
format, e.g. "Fixes #1234". See
https://github.com/blog/1506-closing-issues-via-pull-requests . Please also
write a comment on that issue linking back to this pull request once it is
open. -->
Fixes #17238 

#### Brief description of what is fixed or changed
Added relational operator printer for following languages:
1. glsl
2. js
3. julia
4. mathematica
5. octave
6. rust

I have also verified that they are correct. Added tests for same.
Ping @sylee957 
#### Other comments


#### Release Notes

<!-- Write the release notes for this release below. See
https://github.com/sympy/sympy/wiki/Writing-Release-Notes for more information
on how to write release notes. The bot will check your release notes
automatically to see if they are formatted correctly. -->

<!-- BEGIN RELEASE NOTES -->
- printing
    - added relational operator printing for various languages
<!-- END RELEASE NOTES -->


Problem statement:
Relational printing
```python3
from sympy import *

from sympy.printing.ccode import ccode
from sympy.printing.cxxcode import cxxcode
from sympy.printing.fcode import fcode
from sympy.printing.glsl import glsl_code
from sympy.printing.jscode import jscode
from sympy.printing.julia import julia_code
from sympy.printing.mathematica import mathematica_code
from sympy.printing.octave import octave_code
from sympy.printing.pycode import pycode
from sympy.printing.rcode import rcode
from sympy.printing.rust import rust_code

x = Symbol('x')

print(ccode(Eq(x, 1)))
print(cxxcode(Eq(x, 1)))
print(glsl_code(Eq(x, 1)))
print(fcode(Eq(x, 1)))
print(jscode(Eq(x, 1)))
print(julia_code(Eq(x, 1)))
print(mathematica_code(Eq(x, 1)))
print(octave_code(Eq(x, 1)))
print(pycode(Eq(x, 1)))
print(rcode(Eq(x, 1)))
print(rust_code(Eq(x, 1)))
```
Result
```
x == 1
x == 1
Eq(x, 1)
      x == 1
Eq(x, 1)
Eq(x, 1)
Eq(x, 1)
Eq(x, 1)
(x == 1)
x == 1
Eq(x, 1)
```
glsl, javascript, julia, mathematica, octave, rust code printers are probably printing equality in a wrong way.
They are false-positively looking up for `StrPrinter._print_Relational`

C or Fortran printers are overriding `_print_Relational`, so they are the only things working.

Hints from issue discussion:

Commit message: Added relational operator printer for languages

Patch to review:
diff --git a/sympy/printing/glsl.py b/sympy/printing/glsl.py
index db8e6694cdd7..a8272e3490d9 100644
--- a/sympy/printing/glsl.py
+++ b/sympy/printing/glsl.py
@@ -281,6 +281,12 @@ def _print_int(self, expr):
     def _print_Rational(self, expr):
         return "%s.0/%s.0" % (expr.p, expr.q)
 
+    def _print_Relational(self, expr):
+        lhs_code = self._print(expr.lhs)
+        rhs_code = self._print(expr.rhs)
+        op = expr.rel_op
+        return ("{0} {1} {2}").format(lhs_code, op, rhs_code)
+
     def _print_Add(self, expr, order=None):
         if self._settings['use_operators']:
             return CodePrinter._print_Add(self, expr, order=order)
diff --git a/sympy/printing/jscode.py b/sympy/printing/jscode.py
index 6f456e45fd6a..100dda343f5f 100644
--- a/sympy/printing/jscode.py
+++ b/sympy/printing/jscode.py
@@ -113,6 +113,12 @@ def _print_Rational(self, expr):
         p, q = int(expr.p), int(expr.q)
         return '%d/%d' % (p, q)
 
+    def _print_Relational(self, expr):
+        lhs_code = self._print(expr.lhs)
+        rhs_code = self._print(expr.rhs)
+        op = expr.rel_op
+        return ("{0} {1} {2}").format(lhs_code, op, rhs_code)
+
     def _print_Indexed(self, expr):
         # calculate index for 1d array
         dims = expr.shape
diff --git a/sympy/printing/julia.py b/sympy/printing/julia.py
index b0a75b94b377..d9d6b8e86823 100644
--- a/sympy/printing/julia.py
+++ b/sympy/printing/julia.py
@@ -190,6 +190,11 @@ def multjoin(a, a_str):
             return (sign + multjoin(a, a_str) +
                     divsym + "(%s)" % multjoin(b, b_str))
 
+    def _print_Relational(self, expr):
+        lhs_code = self._print(expr.lhs)
+        rhs_code = self._print(expr.rhs)
+        op = expr.rel_op
+        return ("{0} {1} {2}").format(lhs_code, op, rhs_code)
 
     def _print_Pow(self, expr):
         powsymbol = '^' if all([x.is_number for x in expr.args]) else '.^'
diff --git a/sympy/printing/mathematica.py b/sympy/printing/mathematica.py
index 9ee83f13fde9..cfb2fc1a1090 100644
--- a/sympy/printing/mathematica.py
+++ b/sympy/printing/mathematica.py
@@ -157,6 +157,11 @@ def _print_Mul(self, expr):
             res += '**'.join(self.parenthesize(a, PREC) for a in nc)
         return res
 
+    def _print_Relational(self, expr):
+        lhs_code = self._print(expr.lhs)
+        rhs_code = self._print(expr.rhs)
+        op = expr.rel_op
+        return ("{0} {1} {2}").format(lhs_code, op, rhs_code)
 
     # Primitive numbers
     def _print_Zero(self, expr):
diff --git a/sympy/printing/octave.py b/sympy/printing/octave.py
index 684431e19b2f..b4fc4c0ed567 100644
--- a/sympy/printing/octave.py
+++ b/sympy/printing/octave.py
@@ -209,6 +209,11 @@ def multjoin(a, a_str):
             return (sign + multjoin(a, a_str) +
                     divsym + "(%s)" % multjoin(b, b_str))
 
+    def _print_Relational(self, expr):
+        lhs_code = self._print(expr.lhs)
+        rhs_code = self._print(expr.rhs)
+        op = expr.rel_op
+        return ("{0} {1} {2}").format(lhs_code, op, rhs_code)
 
     def _print_Pow(self, expr):
         powsymbol = '^' if all([x.is_number for x in expr.args]) else '.^'
diff --git a/sympy/printing/rust.py b/sympy/printing/rust.py
index 5ccb50819156..cd3634f7112f 100644
--- a/sympy/printing/rust.py
+++ b/sympy/printing/rust.py
@@ -358,6 +358,12 @@ def _print_Rational(self, expr):
         p, q = int(expr.p), int(expr.q)
         return '%d_f64/%d.0' % (p, q)
 
+    def _print_Relational(self, expr):
+        lhs_code = self._print(expr.lhs)
+        rhs_code = self._print(expr.rhs)
+        op = expr.rel_op
+        return ("{0} {1} {2}").format(lhs_code, op, rhs_code)
+
     def _print_Indexed(self, expr):
         # calculate index for 1d array
         dims = expr.shape
diff --git a/sympy/printing/tests/test_glsl.py b/sympy/printing/tests/test_glsl.py
index 76ab05be2293..53a39d2595cb 100644
--- a/sympy/printing/tests/test_glsl.py
+++ b/sympy/printing/tests/test_glsl.py
@@ -1,4 +1,5 @@
-from sympy.core import pi, oo, symbols, Rational, Integer, GoldenRatio, EulerGamma, Catalan, Lambda, Dummy
+from sympy.core import (pi, symbols, Rational, Integer, GoldenRatio, EulerGamma,
+                        Catalan, Lambda, Dummy, Eq, Ne, Le, Lt, Gt, Ge)
 from sympy.functions import Piecewise, sin, cos, Abs, exp, ceiling, sqrt
 from sympy.utilities.pytest import raises
 from sympy.printing.glsl import GLSLPrinter
@@ -37,6 +38,15 @@ def test_glsl_code_Pow():
     assert glsl_code(x**-1.0) == '1.0/x'
 
 
+def test_glsl_code_Relational():
+    assert glsl_code(Eq(x, y)) == "x == y"
+    assert glsl_code(Ne(x, y)) == "x != y"
+    assert glsl_code(Le(x, y)) == "x <= y"
+    assert glsl_code(Lt(x, y)) == "x < y"
+    assert glsl_code(Gt(x, y)) == "x > y"
+    assert glsl_code(Ge(x, y)) == "x >= y"
+
+
 def test_glsl_code_constants_mathh():
     assert glsl_code(exp(1)) == "float E = 2.71828183;\nE"
     assert glsl_code(pi) == "float pi = 3.14159265;\npi"
diff --git a/sympy/printing/tests/test_jscode.py b/sympy/printing/tests/test_jscode.py
index ff228d2a1206..6b24c98adfd0 100644
--- a/sympy/printing/tests/test_jscode.py
+++ b/sympy/printing/tests/test_jscode.py
@@ -1,5 +1,6 @@
 from sympy.core import (pi, oo, symbols, Rational, Integer, GoldenRatio,
-                        EulerGamma, Catalan, Lambda, Dummy, S)
+                        EulerGamma, Catalan, Lambda, Dummy, S, Eq, Ne, Le,
+                        Lt, Gt, Ge)
 from sympy.functions import (Piecewise, sin, cos, Abs, exp, ceiling, sqrt,
                              sinh, cosh, tanh, asin, acos, acosh, Max, Min)
 from sympy.utilities.pytest import raises
@@ -54,6 +55,16 @@ def test_jscode_Rational():
     assert jscode(Rational(-3, -7)) == "3/7"
 
 
+def test_Relational():
+    assert jscode(Eq(x, y)) == "x == y"
+    assert jscode(Ne(x, y)) == "x != y"
+    assert jscode(Le(x, y)) == "x <= y"
+    assert jscode(Lt(x, y)) == "x < y"
+    assert jscode(Gt(x, y)) == "x > y"
+    assert jscode(Ge(x, y)) == "x >= y"
+
+
+
 def test_jscode_Integer():
     assert jscode(Integer(67)) == "67"
     assert jscode(Integer(-1)) == "-1"
diff --git a/sympy/printing/tests/test_julia.py b/sympy/printing/tests/test_julia.py
index 4aea0db1fc4d..26cf9419b6a5 100644
--- a/sympy/printing/tests/test_julia.py
+++ b/sympy/printing/tests/test_julia.py
@@ -1,5 +1,5 @@
 from sympy.core import (S, pi, oo, symbols, Function, Rational, Integer,
-                        Tuple, Symbol)
+                        Tuple, Symbol, Eq, Ne, Le, Lt, Gt, Ge)
 from sympy.core import EulerGamma, GoldenRatio, Catalan, Lambda, Mul, Pow
 from sympy.functions import Piecewise, sqrt, ceiling, exp, sin, cos
 from sympy.utilities.pytest import raises
@@ -10,7 +10,6 @@
                                             besselk, hankel1, hankel2, airyai,
                                             airybi, airyaiprime, airybiprime)
 from sympy.utilities.pytest import XFAIL
-from sympy.core.compatibility import range
 
 from sympy import julia_code
 
@@ -31,6 +30,15 @@ def test_Rational():
     assert julia_code(Rational(3, 7)*x) == "3*x/7"
 
 
+def test_Relational():
+    assert julia_code(Eq(x, y)) == "x == y"
+    assert julia_code(Ne(x, y)) == "x != y"
+    assert julia_code(Le(x, y)) == "x <= y"
+    assert julia_code(Lt(x, y)) == "x < y"
+    assert julia_code(Gt(x, y)) == "x > y"
+    assert julia_code(Ge(x, y)) == "x >= y"
+
+
 def test_Function():
     assert julia_code(sin(x) ** cos(x)) == "sin(x).^cos(x)"
     assert julia_code(abs(x)) == "abs(x)"
diff --git a/sympy/printing/tests/test_mathematica.py b/sympy/printing/tests/test_mathematica.py
index 787df1af45d7..a2aa5cc16afe 100644
--- a/sympy/printing/tests/test_mathematica.py
+++ b/sympy/printing/tests/test_mathematica.py
@@ -1,5 +1,5 @@
-from sympy.core import (S, pi, oo, symbols, Function,
-                        Rational, Integer, Tuple, Derivative)
+from sympy.core import (S, pi, oo, symbols, Function, Rational, Integer, Tuple,
+                        Derivative, Eq, Ne, Le, Lt, Gt, Ge)
 from sympy.integrals import Integral
 from sympy.concrete import Sum
 from sympy.functions import (exp, sin, cos, fresnelc, fresnels, conjugate, Max,
@@ -32,6 +32,15 @@ def test_Rational():
     assert mcode(Rational(3, 7)*x) == "(3/7)*x"
 
 
+def test_Relational():
+    assert mcode(Eq(x, y)) == "x == y"
+    assert mcode(Ne(x, y)) == "x != y"
+    assert mcode(Le(x, y)) == "x <= y"
+    assert mcode(Lt(x, y)) == "x < y"
+    assert mcode(Gt(x, y)) == "x > y"
+    assert mcode(Ge(x, y)) == "x >= y"
+
+
 def test_Function():
     assert mcode(f(x, y, z)) == "f[x, y, z]"
     assert mcode(sin(x) ** cos(x)) == "Sin[x]^Cos[x]"
diff --git a/sympy/printing/tests/test_octave.py b/sympy/printing/tests/test_octave.py
index a56c68158379..df3b695110d8 100644
--- a/sympy/printing/tests/test_octave.py
+++ b/sympy/printing/tests/test_octave.py
@@ -1,6 +1,6 @@
 from sympy.core import (S, pi, oo, symbols, Function, Rational, Integer,
                         Tuple, Symbol, EulerGamma, GoldenRatio, Catalan,
-                        Lambda, Mul, Pow, Mod)
+                        Lambda, Mul, Pow, Mod, Eq, Ne, Le, Lt, Gt, Ge)
 from sympy.codegen.matrix_nodes import MatrixSolve
 from sympy.functions import (arg, atan2, bernoulli, beta, ceiling, chebyshevu,
                              chebyshevt, conjugate, DiracDelta, exp, expint,
@@ -25,10 +25,6 @@
                                                      erfcinv, erfinv, fresnelc,
                                                      fresnels, li, Shi, Si, Li,
                                                      erf2)
-from sympy.polys.polytools import gcd, lcm
-from sympy.ntheory.primetest import isprime
-from sympy.core.compatibility import range
-
 from sympy import octave_code
 from sympy import octave_code as mcode
 
@@ -49,6 +45,15 @@ def test_Rational():
     assert mcode(Rational(3, 7)*x) == "3*x/7"
 
 
+def test_Relational():
+    assert mcode(Eq(x, y)) == "x == y"
+    assert mcode(Ne(x, y)) == "x != y"
+    assert mcode(Le(x, y)) == "x <= y"
+    assert mcode(Lt(x, y)) == "x < y"
+    assert mcode(Gt(x, y)) == "x > y"
+    assert mcode(Ge(x, y)) == "x >= y"
+
+
 def test_Function():
     assert mcode(sin(x) ** cos(x)) == "sin(x).^cos(x)"
     assert mcode(sign(x)) == "sign(x)"
diff --git a/sympy/printing/tests/test_rust.py b/sympy/printing/tests/test_rust.py
index 2e1a5d8c029d..afa0d48374cb 100644
--- a/sympy/printing/tests/test_rust.py
+++ b/sympy/printing/tests/test_rust.py
@@ -1,13 +1,12 @@
 from sympy.core import (S, pi, oo, symbols, Rational, Integer,
-                        GoldenRatio, EulerGamma, Catalan, Lambda, Dummy, Eq)
+                        GoldenRatio, EulerGamma, Catalan, Lambda, Dummy,
+                        Eq, Ne, Le, Lt, Gt, Ge)
 from sympy.functions import (Piecewise, sin, cos, Abs, exp, ceiling, sqrt,
-                             gamma, sign)
+                             sign)
 from sympy.logic import ITE
 from sympy.utilities.pytest import raises
-from sympy.printing.rust import RustCodePrinter
 from sympy.utilities.lambdify import implemented_function
 from sympy.tensor import IndexedBase, Idx
-from sympy.matrices import Matrix, MatrixSymbol
 
 from sympy import rust_code
 
@@ -19,6 +18,15 @@ def test_Integer():
     assert rust_code(Integer(-56)) == "-56"
 
 
+def test_Relational():
+    assert rust_code(Eq(x, y)) == "x == y"
+    assert rust_code(Ne(x, y)) == "x != y"
+    assert rust_code(Le(x, y)) == "x <= y"
+    assert rust_code(Lt(x, y)) == "x < y"
+    assert rust_code(Gt(x, y)) == "x > y"
+    assert rust_code(Ge(x, y)) == "x >= y"
+
+
 def test_Rational():
     assert rust_code(Rational(3, 7)) == "3_f64/7.0"
     assert rust_code(Rational(18, 9)) == "2"


Code review comments:
diff_hunk: @@ -281,6 +281,12 @@ def _print_int(self, expr):
     def _print_Rational(self, expr):
         return "%s.0/%s.0" % (expr.p, expr.q)
 
+    def _print_Relational(self, expr):
+        lhs_code = self._print(expr.lhs)
+        rhs_code = self._print(expr.rhs)
+        op = expr.rel_op
+        return ("{0} {1} {2}").format(lhs_code, op, rhs_code)
path: sympy/printing/glsl.py
text: @user1:
```suggestion
        return "{0} {1} {2}".format(lhs_code, op, rhs_code)
```
Can you remove these additional parentheses here and every below?