Repository: sympy/sympy

Issue:
Allow passing a printer to codegen()
The most common reason to pass a custom code_gen object to codegen() is to specify the printer. We should just add a printer flag to codegen(). See for instance http://www.sympy.org/scipy-2017-codegen-tutorial/notebooks/08-cythonizing.html#5.-Using-a-Custom-Printer-and-an-External-Library-with-autowrap. 

Discussion:

Patch:
diff --git a/doc/Makefile b/doc/Makefile
index 7abc27909e..d2f822b12b 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -114,7 +114,7 @@ _build/cheatsheet/cheatsheet.pdf: cheatsheet/cheatsheet.tex
 	pdflatex -output-directory=_build/cheatsheet cheatsheet/cheatsheet.tex
 	pdflatex -output-directory=_build/cheatsheet cheatsheet/cheatsheet.tex
 
-_build/cheatsheet/combinatoric_cheatsheet.pdf: cheatsheet/combinatoric_cheatsheet.tex
+_build/cheatsheet/cheatsheet.pdf: cheatsheet/combinatoric_cheatsheet.tex
 	mkdir -p _build/cheatsheet
 	pdflatex -output-directory=_build/cheatsheet cheatsheet/combinatoric_cheatsheet.tex
 	pdflatex -output-directory=_build/cheatsheet cheatsheet/combinatoric_cheatsheet.tex
diff --git a/sympy/physics/secondquant.py b/sympy/physics/secondquant.py
index 384a296e33..85f0d00801 100644
--- a/sympy/physics/secondquant.py
+++ b/sympy/physics/secondquant.py
@@ -435,9 +435,6 @@ def apply_operator(self, state):
     def __repr__(self):
         return "AnnihilateBoson(%s)" % self.state
 
-    def _latex(self, printer):
-        return "b_{%s}" % self.state.name
-
 
 class CreateBoson(BosonicOperator, Creator):
     """
@@ -474,9 +471,6 @@ def apply_operator(self, state):
     def __repr__(self):
         return "CreateBoson(%s)" % self.state
 
-    def _latex(self, printer):
-        return "b^\\dagger_{%s}" % self.state.name
-
 B = AnnihilateBoson
 Bd = CreateBoson
 
diff --git a/sympy/physics/wigner.py b/sympy/physics/wigner.py
index 1b3f92cdee..0546046ee4 100644
--- a/sympy/physics/wigner.py
+++ b/sympy/physics/wigner.py
@@ -513,9 +513,6 @@ def wigner_9j(j_1, j_2, j_3, j_4, j_5, j_6, j_7, j_8, j_9, prec=None):
     >>> wigner_9j(1,1,1, 1,1,1, 1,1,0 ,prec=64) # ==1/18
     0.05555555...
 
-    >>> wigner_9j(1/2,1/2,0, 1/2,3/2,1, 0,1,1 ,prec=64) # ==1/6
-    0.1666666...
-
     It is an error to have arguments that are not integer or half
     integer values or do not fulfill the triangle relation::
 
@@ -536,19 +533,15 @@ def wigner_9j(j_1, j_2, j_3, j_4, j_5, j_6, j_7, j_8, j_9, prec=None):
     for finite precision arithmetic and only useful for a computer
     algebra system [Rasch03]_.
     """
-
+    imin = 0
     imax = min(j_1 + j_9, j_2 + j_6, j_4 + j_8)
-    j_sum = j_1 + j_2 + j_9 + j_6 + j_4 + j_8
+
     sumres = 0
-    for kk in range(0, 2*(int(imax) + 1)):
-        k = S.Half*kk
-        try:
-            sumres +=(-1)**(kk+2*j_sum)*(kk + 1) * \
-            racah(j_1, j_2, j_9, j_6, j_3, k, prec) * \
-            racah(j_4, j_6, j_8, j_2, j_5, k, prec) * \
-            racah(j_1, j_4, j_9, j_8, j_7, k, prec)
-        except ValueError:
-            pass
+    for kk in range(imin, int(imax) + 1):
+        sumres = sumres + (2 * kk + 1) * \
+            racah(j_1, j_2, j_9, j_6, j_3, kk, prec) * \
+            racah(j_4, j_6, j_8, j_2, j_5, kk, prec) * \
+            racah(j_1, j_4, j_9, j_8, j_7, kk, prec)
     return sumres
 
 
diff --git a/sympy/printing/latex.py b/sympy/printing/latex.py
index 93647f3ceb..73a0b41d8b 100644
--- a/sympy/printing/latex.py
+++ b/sympy/printing/latex.py
@@ -372,7 +372,6 @@ def _print_Gradient(self, expr):
         return r"\nabla\cdot %s" % self.parenthesize(func, PRECEDENCE['Mul'])
 
     def _print_Mul(self, expr):
-        from sympy.core.power import Pow
         include_parens = False
         if _coeff_isneg(expr):
             expr = -expr
@@ -417,11 +416,10 @@ def convert(expr):
                     last_term_tex = term_tex
                 return _tex
 
-        if denom is S.One and Pow(1, -1, evaluate=False) not in expr.args:
+        if denom is S.One:
             # use the original expression here, since fraction() may have
             # altered it when producing numer and denom
             tex += convert(expr)
-
         else:
             snumer = convert(numer)
             sdenom = convert(denom)
diff --git a/sympy/simplify/cse_main.py b/sympy/simplify/cse_main.py
index cdbab4f608..d923a575ed 100644
--- a/sympy/simplify/cse_main.py
+++ b/sympy/simplify/cse_main.py
@@ -447,7 +447,7 @@ def _find_opts(expr):
     # split muls into commutative
     commutative_muls = OrderedSet()
     for m in muls:
-        c, nc = m.args_cnc(cset=False)
+        c, nc = m.args_cnc(cset=True)
         if c:
             c_mul = m.func(*c)
             if nc:
diff --git a/sympy/utilities/codegen.py b/sympy/utilities/codegen.py
index 3cc74b237f..a8a1ba9d73 100644
--- a/sympy/utilities/codegen.py
+++ b/sympy/utilities/codegen.py
@@ -1945,7 +1945,7 @@ def dump_rs(self, routines, f, prefix, header=True, empty=True):
 
 
 
-def get_code_generator(language, project=None, standard=None):
+def get_code_generator(language, project=None, standard=None, printer = None):
     if language == 'C':
         if standard is None:
             pass
@@ -1959,7 +1959,7 @@ def get_code_generator(language, project=None, standard=None):
                     "RUST": RustCodeGen}.get(language.upper())
     if CodeGenClass is None:
         raise ValueError("Language '%s' is not supported." % language)
-    return CodeGenClass(project)
+    return CodeGenClass(project, printer)
 
 
 #
@@ -1969,7 +1969,7 @@ def get_code_generator(language, project=None, standard=None):
 
 def codegen(name_expr, language=None, prefix=None, project="project",
             to_files=False, header=True, empty=True, argument_sequence=None,
-            global_vars=None, standard=None, code_gen=None):
+            global_vars=None, standard=None, code_gen=None, printer = None):
     """Generate source code for expressions in a given language.
 
     Parameters
@@ -2103,7 +2103,7 @@ def codegen(name_expr, language=None, prefix=None, project="project",
     else:
         if code_gen is not None:
             raise ValueError("You cannot specify both language and code_gen.")
-        code_gen = get_code_generator(language, project, standard)
+        code_gen = get_code_generator(language, project, standard, printer)
 
     if isinstance(name_expr[0], string_types):
         # single tuple is given, turn it into a singleton list with a tuple.


Test patch:
diff --git a/sympy/external/tests/test_sage.py b/sympy/external/tests/test_sage.py
index 866bf7d786..e20c7f8785 100644
--- a/sympy/external/tests/test_sage.py
+++ b/sympy/external/tests/test_sage.py
@@ -34,15 +34,6 @@
 
 from sympy.utilities.pytest import XFAIL
 
-def is_trivially_equal(lhs, rhs):
-    """
-    True if lhs and rhs are trivially equal.
-
-    Use this for comparison of Sage expressions. Otherwise you
-    may start the whole proof machinery which may not exist at
-    the time of testing.
-    """
-    assert (lhs - rhs).is_trivial_zero()
 
 def check_expression(expr, var_symbols, only_from_sympy=False):
     """
@@ -82,7 +73,7 @@ def check_expression(expr, var_symbols, only_from_sympy=False):
     # Do the actual checks:
     if not only_from_sympy:
         assert sympy.S(e_sage) == e_sympy
-    is_trivially_equal(e_sage, sage.SR(e_sympy))
+    assert e_sage == sage.SR(e_sympy)
 
 
 def test_basics():
@@ -116,40 +107,40 @@ def test_real():
 
 def test_E():
     assert sympy.sympify(sage.e) == sympy.E
-    is_trivially_equal(sage.e, sage.SR(sympy.E))
+    assert sage.e == sage.SR(sympy.E)
 
 
 def test_pi():
     assert sympy.sympify(sage.pi) == sympy.pi
-    is_trivially_equal(sage.pi, sage.SR(sympy.pi))
+    assert sage.pi == sage.SR(sympy.pi)
 
 
 def test_euler_gamma():
     assert sympy.sympify(sage.euler_gamma) == sympy.EulerGamma
-    is_trivially_equal(sage.euler_gamma, sage.SR(sympy.EulerGamma))
+    assert sage.euler_gamma == sage.SR(sympy.EulerGamma)
 
 
 def test_oo():
     assert sympy.sympify(sage.oo) == sympy.oo
-    assert sage.oo == sage.SR(sympy.oo).pyobject()
+    assert sage.oo == sage.SR(sympy.oo)
     assert sympy.sympify(-sage.oo) == -sympy.oo
-    assert -sage.oo == sage.SR(-sympy.oo).pyobject()
+    assert -sage.oo == sage.SR(-sympy.oo)
     #assert sympy.sympify(sage.UnsignedInfinityRing.gen()) == sympy.zoo
     #assert sage.UnsignedInfinityRing.gen() == sage.SR(sympy.zoo)
 
 def test_NaN():
     assert sympy.sympify(sage.NaN) == sympy.nan
-    is_trivially_equal(sage.NaN, sage.SR(sympy.nan))
+    assert sage.NaN == sage.SR(sympy.nan)
 
 
 def test_Catalan():
     assert sympy.sympify(sage.catalan) == sympy.Catalan
-    is_trivially_equal(sage.catalan, sage.SR(sympy.Catalan))
+    assert sage.catalan == sage.SR(sympy.Catalan)
 
 
 def test_GoldenRation():
     assert sympy.sympify(sage.golden_ratio) == sympy.GoldenRatio
-    is_trivially_equal(sage.golden_ratio, sage.SR(sympy.GoldenRatio))
+    assert sage.golden_ratio == sage.SR(sympy.GoldenRatio)
 
 
 def test_functions():
@@ -204,7 +195,7 @@ def test_issue_4023():
     i = sympy.integrate(log(x)/a, (x, a, a + 1))
     i2 = sympy.simplify(i)
     s = sage.SR(i2)
-    is_trivially_equal(s, -log(a) + log(a + 1) + log(a + 1)/a - 1/a)
+    assert s == (a*log(1 + a) - a*log(a) + log(1 + a) - 1)/a
 
 def test_integral():
     #test Sympy-->Sage
@@ -228,7 +219,7 @@ def test_undefined_function():
     sf = sage.function('f')
     x = sympy.symbols('x')
     sx = sage.var('x')
-    is_trivially_equal(sf(sx), f(x)._sage_())
+    assert bool(sf(sx) == f(x)._sage_())
     #assert bool(f == sympy.sympify(sf))
 
 def test_abstract_function():
diff --git a/sympy/physics/tests/test_secondquant.py b/sympy/physics/tests/test_secondquant.py
index d8276ffbcd..0a468b6306 100644
--- a/sympy/physics/tests/test_secondquant.py
+++ b/sympy/physics/tests/test_secondquant.py
@@ -14,7 +14,6 @@
 
 from sympy.core.compatibility import range
 from sympy.utilities.pytest import XFAIL, slow
-from sympy.printing.latex import latex
 
 
 def test_PermutationOperator():
@@ -91,7 +90,6 @@ def test_operator():
 def test_create():
     i, j, n, m = symbols('i,j,n,m')
     o = Bd(i)
-    assert latex(o) == "b^\\dagger_{i}"
     assert isinstance(o, CreateBoson)
     o = o.subs(i, j)
     assert o.atoms(Symbol) == {j}
@@ -104,7 +102,6 @@ def test_create():
 def test_annihilate():
     i, j, n, m = symbols('i,j,n,m')
     o = B(i)
-    assert latex(o) == "b_{i}"
     assert isinstance(o, AnnihilateBoson)
     o = o.subs(i, j)
     assert o.atoms(Symbol) == {j}
diff --git a/sympy/printing/tests/test_latex.py b/sympy/printing/tests/test_latex.py
index bf62ccd337..201b23ef49 100644
--- a/sympy/printing/tests/test_latex.py
+++ b/sympy/printing/tests/test_latex.py
@@ -1631,12 +1631,6 @@ def test_issue_12886():
     assert latex(m__1**2 + l__1**2) == r'\left(l^{1}\right)^{2} + \left(m^{1}\right)^{2}'
 
 
-def test_issue_13559():
-    from sympy.parsing.sympy_parser import parse_expr
-    expr = parse_expr('5/1', evaluate=False)
-    assert latex(expr) == r"\frac{5}{1}"
-
-
 def test_latex_UnevaluatedExpr():
     x = symbols("x")
     he = UnevaluatedExpr(1/x)
diff --git a/sympy/simplify/tests/test_cse.py b/sympy/simplify/tests/test_cse.py
index 41edc36c72..be0fe1ba0b 100644
--- a/sympy/simplify/tests/test_cse.py
+++ b/sympy/simplify/tests/test_cse.py
@@ -521,8 +521,3 @@ def test_issue_13000():
     eq = x/(-4*x**2 + y**2)
     cse_eq = cse(eq)[1][0]
     assert cse_eq == eq
-
-
-def test_unevaluated_mul():
-    eq = Mul(x + y, x + y, evaluate=False)
-    assert cse(eq) == ([(x0, x + y)], [x0**2])
diff --git a/sympy/utilities/tests/test_codegen.py b/sympy/utilities/tests/test_codegen.py
index 07ced5bbe4..2a4b1a98ad 100644
--- a/sympy/utilities/tests/test_codegen.py
+++ b/sympy/utilities/tests/test_codegen.py
@@ -1506,3 +1506,33 @@ def test_custom_codegen():
     result = codegen(('expr', expr), header=False, empty=False, code_gen=gen)
     source = result[0][1]
     assert source == expected
+
+def test_c_with_printer():
+    #issue 13586
+    from sympy.printing.ccode import C99CodePrinter
+    class CustomPrinter(C99CodePrinter):
+        def _print_Pow(self, expr):
+            return "fastpow({}, {})".format(self._print(expr.base),
+                                            self._print(expr.exp))
+
+    x = symbols('x')
+    expr = x**3
+    expected =[
+        ("file.c",
+        "#include \"file.h\"\n"
+        "#include <math.h>\n"
+        "double test(double x) {\n"
+        "   double test_result;\n"
+        "   test_result = fastpow(x, 3);\n"
+        "   return test_result;\n"
+        "}\n"),
+        ("file.h",
+        "#ifndef PROJECT__FILE__H\n"
+        "#define PROJECT__FILE__H\n"
+        "double test(double x);\n"
+        "#endif\n")
+    ]
+    with warnings.catch_warnings():
+        warnings.filterwarnings("ignore", category=SymPyDeprecationWarning)
+        result = codegen(("test", expr), "C","file", header=False, empty=False, printer = CustomPrinter())
+        assert result == expected