The patch looks fine to me, however I'm not familiar with fortran. But
no one objected so far, so I pushed it in, thanks.

Vinzent

2010/2/24 Toon Verstraelen <toon.verstrae...@gmail.com>:
> ---
>  doc/src/modules/printing.txt       |   96 +++++++++++
>  sympy/__init__.py                  |    2 +-
>  sympy/printing/__init__.py         |    1 +
>  sympy/printing/fcode.py            |  326 
> ++++++++++++++++++++++++++++++++++++
>  sympy/printing/tests/test_fcode.py |  217 ++++++++++++++++++++++++
>  5 files changed, 641 insertions(+), 1 deletions(-)
>  create mode 100644 sympy/printing/fcode.py
>  create mode 100644 sympy/printing/tests/test_fcode.py
>
> diff --git a/doc/src/modules/printing.txt b/doc/src/modules/printing.txt
> index d6178e3..d6714f0 100644
> --- a/doc/src/modules/printing.txt
> +++ b/doc/src/modules/printing.txt
> @@ -84,6 +84,102 @@ This class implements Python printing. Usage::
>     x = Symbol('x')
>     e = sin(x) + 5*x**3
>
> +fcode
> +-----
> +
> +The fcode function translates a sympy expression into Fortran code. The main
> +purpose is to take away the burden of manually translating long mathematical
> +expressions. Therefore the resulting expression should also require no (or 
> very
> +little) manual tweaking to make it compilable. The optional arguments of 
> fcode
> +can be used to fine-tune the behavior of fcode in such a way that manual 
> changes
> +in the result are no longer needed.
> +
> +.. module:: sympy.printing.fcode
> +.. autofunction:: fcode
> +.. autofunction:: print_fcode
> +
> +Two basic examples:
> +
> +    >>> from sympy import *
> +    >>> x = symbols("x")
> +    >>> fcode(sqrt(1-x**2))
> +    '      sqrt(1 - x**2)'
> +    >>> fcode((3 + 4*I)/(1 - conjugate(x)))
> +    '      (cmplx(3,4))/(1 - conjg(x))'
> +
> +An example where line wrapping is required:
> +
> +    >>> expr = sqrt(1-x**2).series(x,n=20).removeO()
> +    >>> print fcode(expr)
> +          1 - x**2/2 - x**4/8 - x**6/16 - 5*x**8/128 - 7*x**10/256 - 21*x
> +         @ **12/1024 - 33*x**14/2048 - 429*x**16/32768 - 715*x**18/65536
> +
> +In case of line wrapping, it is handy to include the assignment so that lines
> +are wrapped properly when the assignment part is added.
> +
> +    >>> print fcode(expr, assign_to="var")
> +          var = 1 - x**2/2 - x**4/8 - x**6/16 - 5*x**8/128 - 7*x**10/256 -
> +         @ 21*x**12/1024 - 33*x**14/2048 - 429*x**16/32768 - 715*x**18/65536
> +
> +Also for piecewise functions, the assign_to option can be helpful:
> +
> +    >>> print fcode(Piecewise((x,x<1),(x**2,True)), assign_to="var")
> +          if (x < 1) then
> +            var = x
> +          else
> +            var = x**2
> +          end if
> +
> +Note that only top-level piecewise functions are supported due to the lack of
> +a conditional operator in Fortran. Nested piecewise functions would require 
> the
> +introduction of temporary variables, which is a type of expression 
> manipulation
> +that goes beyond the scope of fcode.
> +
> +By default, number symbols such as ``pi`` and ``E`` are detected and defined 
> as
> +Fortran parameters. The precision of the constants can be tuned with the
> +precision argument. Parameter definitions are easily avoided using the ``N``
> +function.
> +
> +    >>> print fcode(x - pi**2 - E)
> +          parameter (E = 2.71828182845905)
> +          parameter (pi = 3.14159265358979)
> +          x - E - pi**2
> +    >>> print fcode(x - pi**2 - E, precision=25)
> +          parameter (E = 2.718281828459045235360287)
> +          parameter (pi = 3.141592653589793238462643)
> +          x - E - pi**2
> +    >>> print fcode(N(x - pi**2, 25))
> +          -9.869604401089358618834491 + x
> +
> +When some functions are not part of the Fortran standard, it might be 
> desirable
> +to introduce the names of user-defined functions in the Fortran expression.
> +
> +    >>> print fcode(1 - gamma(x)**2, user_functions={gamma: 'mygamma'})
> +          1 - mygamma(x)**2
> +
> +However, when the user_functions argument is not provided, fcode attempts to
> +use a reasonable default and adds a comment to inform the user of the issue.
> +
> +    >>> print fcode(1 - gamma(x)**2)
> +    C     Not Fortran 77:
> +    C     gamma(x)
> +          1 - gamma(x)**2
> +
> +By default the output is human readable code, ready for copy and paste. With 
> the
> +option ``human=False``, the return value is suitable for post-processing with
> +source code generators that write routines with multiple instructions. The
> +return value is a three-tuple containing: (i) the list of number symbols that
> +must be defined as 'Fortran parameters', (ii) a list functions that can not 
> be
> +translated in pure Fortran and (iii) a string of Fortran code. A few 
> examples:
> +
> +    >>> fcode(1 - gamma(x)**2, human=False)
> +    ([], set([gamma(x)]), '      1 - gamma(x)**2')
> +    >>> fcode(1 - sin(x)**2, human=False)
> +    ([], set(), '      1 - sin(x)**2')
> +    >>> fcode(x - pi**2, human=False)
> +    ([('pi', 3.14159265358979)], set(), '      x - pi**2')
> +
> +
>  Preview
>  -------
>
> diff --git a/sympy/__init__.py b/sympy/__init__.py
> index 2cc73f8..81cd4a5 100644
> --- a/sympy/__init__.py
> +++ b/sympy/__init__.py
> @@ -38,7 +38,7 @@ def __sympy_debug():
>  from plotting import Plot, textplot
>  from printing import pretty, pretty_print, pprint, pprint_use_unicode, \
>     pprint_try_use_unicode, print_gtk, print_tree
> -from printing import ccode, latex, preview
> +from printing import ccode, fcode, latex, preview
>  from printing import python, print_python, srepr, sstr, sstrrepr
>
>  evalf._create_evalf_table()
> diff --git a/sympy/printing/__init__.py b/sympy/printing/__init__.py
> index 1ade76d..40065a0 100644
> --- a/sympy/printing/__init__.py
> +++ b/sympy/printing/__init__.py
> @@ -5,6 +5,7 @@
>  from mathml import mathml, print_mathml
>  from python import python, print_python
>  from ccode import ccode, print_ccode
> +from fcode import fcode, print_fcode
>  from gtk import *
>
>  from preview import preview
> diff --git a/sympy/printing/fcode.py b/sympy/printing/fcode.py
> new file mode 100644
> index 0000000..6211920
> --- /dev/null
> +++ b/sympy/printing/fcode.py
> @@ -0,0 +1,326 @@
> +"""
> +Fortran code printer
> +
> +The FCodePrinter converts single sympy expressions into single Fortran
> +expressions, using the functions defined in the Fortran 77 standard where
> +possible. Some useful pointers to Fortran can be found on wikipedia:
> +
> +http://en.wikipedia.org/wiki/Fortran
> +
> +Most of the code below is based on the "Professional Programmer\'s Guide to
> +Fortran77" by Clive G. Page:
> +
> +http://www.star.le.ac.uk/~cgp/prof77.html
> +
> +Fortran is a case-insensitive language. This might cause trouble because 
> sympy
> +is case sensitive. The implementation below does not care and leaves the
> +responsibility for generating properly cased Fortran code to the user.
> +"""
> +
> +
> +from str import StrPrinter
> +from sympy.printing.precedence import precedence
> +from sympy.core import S, Add, I
> +from sympy.core.numbers import NumberSymbol
> +from sympy.functions import sin, cos, tan, asin, acos, atan, atan2, sinh, \
> +    cosh, tanh, sqrt, log, exp, abs, sign, conjugate, Piecewise
> +from sympy.utilities.iterables import postorder_traversal
> +
> +
> +implicit_functions = set([
> +    sin, cos, tan, asin, acos, atan, atan2, sinh, cosh, tanh, sqrt, log, exp,
> +    abs, sign, conjugate
> +])
> +
> +
> +class FCodePrinter(StrPrinter):
> +    """A printer to convert sympy expressions to strings of Fortran code"""
> +    printmethod = "_fcode_"
> +
> +    def doprint(self, expr):
> +        """Returns Fortran code for expr (as a string)"""
> +        # keep a set of expressions that are not strictly translatable to
> +        # Fortran.
> +        self.not_fortran = set([])
> +
> +        lines = []
> +        if isinstance(expr, Piecewise):
> +            # support for top-level Piecewise function
> +            for i, (e, c) in enumerate(expr.args):
> +                if i == 0:
> +                    lines.append("      if (%s) then" % self._print(c))
> +                elif i == len(expr.args)-1 and c == True:
> +                    lines.append("      else")
> +                else:
> +                    lines.append("      else if (%s) then" % self._print(c))
> +                if self._settings["assign_to"] is None:
> +                    lines.append("        %s" % self._print(e))
> +                else:
> +                    lines.append("        %s = %s" % 
> (self._settings["assign_to"], self._print(e)))
> +            lines.append("      end if")
> +            return "\n".join(lines)
> +        else:
> +            line = StrPrinter.doprint(self, expr)
> +            if self._settings["assign_to"] is None:
> +                return "      %s" % line
> +            else:
> +                return "      %s = %s" % (self._settings["assign_to"], line)
> +
> +    def _print_Add(self, expr):
> +        # purpose: print complex numbers nicely in Fortran.
> +        # collect the purely real and purely imaginary parts:
> +        pure_real = []
> +        pure_imaginary = []
> +        mixed = []
> +        for arg in expr.args:
> +            if arg.is_real and arg.is_number:
> +                pure_real.append(arg)
> +            elif arg.is_imaginary and arg.is_number:
> +                pure_imaginary.append(arg)
> +            else:
> +                mixed.append(arg)
> +        if len(pure_imaginary) > 0:
> +            if len(mixed) > 0:
> +                PREC = precedence(expr)
> +                term = Add(*mixed)
> +                t = self._print(term)
> +                if t.startswith('-'):
> +                    sign = "-"
> +                    t = t[1:]
> +                else:
> +                    sign = "+"
> +                if precedence(term) < PREC:
> +                    t = "(%s)" % t
> +
> +                return "cmplx(%s,%s) %s %s" % (
> +                    self._print(Add(*pure_real)),
> +                    self._print(-I*Add(*pure_imaginary)),
> +                    sign, t,
> +                )
> +            else:
> +                return "cmplx(%s,%s)" % (
> +                    self._print(Add(*pure_real)),
> +                    self._print(-I*Add(*pure_imaginary)),
> +                )
> +        else:
> +            return StrPrinter._print_Add(self, expr)
> +
> +    def _print_Function(self, expr):
> +        name = self._settings["user_functions"].get(expr.__class__)
> +        if name is None:
> +            if expr.func == conjugate:
> +                name = "conjg"
> +            else:
> +                name = expr.func.__name__
> +            if expr.func not in implicit_functions:
> +                self.not_fortran.add(expr)
> +        return "%s(%s)" % (name, self.stringify(expr.args, ", "))
> +
> +    _print_Factorial = _print_Function
> +
> +    def _print_ImaginaryUnit(self, expr):
> +        # purpose: print complex numbers nicely in Fortran.
> +        return "cmplx(0,1)"
> +
> +    def _print_int(self, expr):
> +        return str(expr)
> +
> +    def _print_Mul(self, expr):
> +        # purpose: print complex numbers nicely in Fortran.
> +        if expr.is_imaginary and expr.is_number:
> +            return "cmplx(0,%s)" % (
> +                self._print(-I*expr)
> +            )
> +        else:
> +            return StrPrinter._print_Mul(self, expr)
> +
> +    def _print_NumberSymbol(self, expr):
> +        # Standard Fortran has no predefined constants. Write their string
> +        # representation, and assume parameter statements are defined 
> elsewhere
> +        # in the code to make this work.
> +        return str(expr)
> +
> +    _print_Catalan = _print_NumberSymbol
> +    _print_EulerGamma = _print_NumberSymbol
> +    _print_Exp1 = _print_NumberSymbol
> +    _print_GoldenRatio = _print_NumberSymbol
> +    _print_Pi = _print_NumberSymbol
> +
> +    def _print_Pow(self, expr):
> +        PREC = precedence(expr)
> +        if expr.exp is S.NegativeOne:
> +            return '1.0/%s'%(self.parenthesize(expr.base, PREC))
> +        elif expr.exp == 0.5:
> +            return 'sqrt(%s)' % self._print(expr.base)
> +        else:
> +            return StrPrinter._print_Pow(self, expr)
> +
> +    def _print_Rational(self, expr):
> +        p, q = int(expr.p), int(expr.q)
> +        return '%d.0/%d.0' % (p, q)
> +
> +    def _print_not_fortran(self, expr):
> +        self.not_fortran.add(expr)
> +        return StrPrinter.emptyPrinter(self, expr)
> +
> +    # The following can not be simply translated into Fortran.
> +    _print_Basic = _print_not_fortran
> +    _print_ComplexInfinity = _print_not_fortran
> +    _print_Derivative = _print_not_fortran
> +    _print_dict = _print_not_fortran
> +    _print_Dummy = _print_not_fortran
> +    _print_ExprCondPair = _print_not_fortran
> +    _print_GeometryEntity = _print_not_fortran
> +    _print_Infinity = _print_not_fortran
> +    _print_Integral = _print_not_fortran
> +    _print_Interval = _print_not_fortran
> +    _print_Limit = _print_not_fortran
> +    _print_list = _print_not_fortran
> +    _print_Matrix = _print_not_fortran
> +    _print_DeferredVector = _print_not_fortran
> +    _print_NaN = _print_not_fortran
> +    _print_NegativeInfinity = _print_not_fortran
> +    _print_Normal = _print_not_fortran
> +    _print_Order = _print_not_fortran
> +    _print_PDF = _print_not_fortran
> +    _print_RootOf = _print_not_fortran
> +    _print_RootsOf = _print_not_fortran
> +    _print_RootSum = _print_not_fortran
> +    _print_Sample = _print_not_fortran
> +    _print_SMatrix = _print_not_fortran
> +    _print_tuple = _print_not_fortran
> +    _print_Uniform = _print_not_fortran
> +    _print_Unit = _print_not_fortran
> +    _print_Wild = _print_not_fortran
> +    _print_WildFunction = _print_not_fortran
> +
> +
> +def wrap_fortran(lines):
> +    """Wrap long Fortran lines
> +
> +       Argument:
> +         lines  --  a list of lines (without \\n character)
> +
> +       A comment line is split at white space. Code lines are split with a 
> more
> +       complex rule to give nice results.
> +    """
> +    # routine to find split point in a code line
> +    my_alnum = set("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_")
> +    my_white = set(" \t()")
> +    def split_pos_code(line, endpos):
> +        if len(line) <= endpos:
> +            return len(line)
> +        pos = endpos
> +        split = lambda pos: \
> +            (line[pos] in my_alnum and line[pos-1] not in my_alnum) or \
> +            (line[pos] not in my_alnum and line[pos-1] in my_alnum) or \
> +            (line[pos] in my_white and line[pos-1] not in my_white) or \
> +            (line[pos] not in my_white and line[pos-1] in my_white)
> +        while not split(pos):
> +            pos -= 1
> +            if pos == 0:
> +                return endpos
> +        return pos
> +    # split line by line and add the splitted lines to result
> +    result = []
> +    for line in lines:
> +        if line.startswith("      "):
> +            # code line
> +            pos = split_pos_code(line, 72)
> +            hunk = line[:pos].rstrip()
> +            line = line[pos:].lstrip()
> +            result.append(hunk)
> +            while len(line) > 0:
> +                pos = split_pos_code(line, 65)
> +                hunk = line[:pos].rstrip()
> +                line = line[pos:].lstrip()
> +                result.append("     @ %s" % hunk)
> +        elif line.startswith("C"):
> +            # comment line
> +            if len(line) > 72:
> +                pos = line.rfind(" ", 6, 72)
> +                if pos == -1:
> +                    pos = 72
> +                hunk = line[:pos]
> +                line = line[pos:].lstrip()
> +                result.append(hunk)
> +                while len(line) > 0:
> +                    pos = line.rfind(" ", 0, 66)
> +                    if pos == -1:
> +                        pos = 66
> +                    hunk = line[:pos]
> +                    line = line[pos:].lstrip()
> +                    result.append("C     %s" % hunk)
> +            else:
> +                result.append(line)
> +        else:
> +            result.append(line)
> +    return result
> +
> +
> +def fcode(expr, assign_to=None, precision=15, user_functions={}, human=True):
> +    """Converts an expr to a string of Fortran 77 code
> +
> +       Arguments:
> +         expr  --  a sympy expression to be converted
> +
> +       Optional arguments:
> +         assign_to  --  When given, the argument is used as the name of the
> +                        variable to which the Fortran expression is assigned.
> +                        (This is helpful in case of line-wrapping.)
> +         precision  --  the precision for numbers such as pi [default=15]
> +         user_functions  --  A dictionary where keys are FunctionClass 
> instances
> +                             and values are there string representations.
> +         human  --  If True, the result is a single string that may contain
> +                    some parameter statements for the number symbols. If
> +                    False, the same information is returned in a more
> +                    programmer-friendly data structure.
> +
> +       >>> from sympy import fcode, symbols, Rational, pi, sin
> +       >>> x, tau = symbols(["x", "tau"])
> +       >>> fcode((2*tau)**Rational(7,2))
> +       '      8*sqrt(2)*tau**(7.0/2.0)'
> +       >>> fcode(sin(x), assign_to="s")
> +       '      s = sin(x)'
> +       >>> print fcode(pi)
> +             parameter (pi = 3.14159265358979)
> +             pi
> +
> +    """
> +    # find all number symbols
> +    number_symbols = set([])
> +    for sub in postorder_traversal(expr):
> +        if isinstance(sub, NumberSymbol):
> +            number_symbols.add(sub)
> +    number_symbols = [(str(ns), ns.evalf(precision)) for ns in 
> sorted(number_symbols)]
> +    # run the printer
> +    profile = {
> +        "full_prec": False, # programmers don't care about trailing zeros.
> +        "assign_to": assign_to,
> +        "user_functions": user_functions,
> +    }
> +    printer = FCodePrinter(profile)
> +    result = printer.doprint(expr)
> +    # format the output
> +    if human:
> +        lines = []
> +        if len(printer.not_fortran) > 0:
> +            lines.append("C     Not Fortran 77:")
> +            for expr in sorted(printer.not_fortran):
> +                lines.append("C     %s" % expr)
> +        for name, value in number_symbols:
> +            lines.append("      parameter (%s = %s)" % (name, value))
> +        lines.extend(result.split("\n"))
> +        lines = wrap_fortran(lines)
> +        return "\n".join(lines)
> +    else:
> +        return number_symbols, printer.not_fortran, result
> +
> +
> +def print_fcode(expr, assign_to=None, precision=15, user_functions={}):
> +    """Prints the Fortran representation of the given expression.
> +
> +       See fcode for the meaning of the optional arguments.
> +    """
> +    print fcode(expr, assign_to, precision, user_functions)
> +
> diff --git a/sympy/printing/tests/test_fcode.py 
> b/sympy/printing/tests/test_fcode.py
> new file mode 100644
> index 0000000..44cb24c
> --- /dev/null
> +++ b/sympy/printing/tests/test_fcode.py
> @@ -0,0 +1,217 @@
> +from sympy import sin, cos, atan2, gamma, conjugate, sqrt, Factorial, \
> +    Integral, Piecewise, Add, diff, symbols, raises
> +from sympy import Catalan, EulerGamma, E, GoldenRatio, I, pi
> +from sympy import Function, Rational, Integer
> +
> +from sympy.printing.fcode import fcode, wrap_fortran
> +
> +
> +def test_printmethod():
> +    x = symbols('x')
> +    class nint(Function):
> +        def _fcode_(self, printer):
> +            return "nint(%s)" % printer._print(self.args[0])
> +    assert fcode(nint(x)) == "      nint(x)"
> +
> +def test_fcode_Pow():
> +    x, y = symbols('xy')
> +    assert fcode(x**3) == "      x**3"
> +    assert fcode(x**(y**3)) == "      x**(y**3)"
> +    assert fcode(1/(sin(x)*3.5)**(x - y**x)/(x**2 + y)) == \
> +        "      (3.5*sin(x))**(-x + y**x)/(y + x**2)"
> +    assert fcode(sqrt(x)) == '      sqrt(x)'
> +    assert fcode(x**0.5) == '      sqrt(x)'
> +    assert fcode(x**Rational(1,2)) == '      sqrt(x)'
> +
> +def test_fcode_Rational():
> +    assert fcode(Rational(3,7)) == "      3.0/7.0"
> +    assert fcode(Rational(18,9)) == "      2"
> +    assert fcode(Rational(3,-7)) == "      -3.0/7.0"
> +    assert fcode(Rational(-3,-7)) == "      3.0/7.0"
> +
> +def test_fcode_Integer():
> +    assert fcode(Integer(67)) == "      67"
> +    assert fcode(Integer(-1)) == "      -1"
> +
> +def test_fcode_functions():
> +    x, y = symbols('xy')
> +    assert fcode(sin(x) ** cos(y)) == "      sin(x)**cos(y)"
> +
> +def test_fcode_NumberSymbol():
> +    assert fcode(Catalan) == '      parameter (Catalan = 
> 0.915965594177219)\n      Catalan'
> +    assert fcode(EulerGamma) == '      parameter (EulerGamma = 
> 0.577215664901533)\n      EulerGamma'
> +    assert fcode(E) == '      parameter (E = 2.71828182845905)\n      E'
> +    assert fcode(GoldenRatio) == '      parameter (GoldenRatio = 
> 1.61803398874989)\n      GoldenRatio'
> +    assert fcode(pi) == '      parameter (pi = 3.14159265358979)\n      pi'
> +    assert fcode(pi,precision=5) == '      parameter (pi = 3.1416)\n      pi'
> +    assert fcode(Catalan,human=False) == ([('Catalan', Catalan.evalf(15))], 
> set([]), '      Catalan')
> +    assert fcode(EulerGamma,human=False) == ([('EulerGamma', 
> EulerGamma.evalf(15))], set([]), '      EulerGamma')
> +    assert fcode(E,human=False) == ([('E', E.evalf(15))], set([]), '      E')
> +    assert fcode(GoldenRatio,human=False) == ([('GoldenRatio', 
> GoldenRatio.evalf(15))], set([]), '      GoldenRatio')
> +    assert fcode(pi,human=False) == ([('pi', pi.evalf(15))], set([]), '      
> pi')
> +    assert fcode(pi,precision=5,human=False) == ([('pi', pi.evalf(5))], 
> set([]), '      pi')
> +
> +def test_fcode_complex():
> +    assert fcode(I) == "      cmplx(0,1)"
> +    x = symbols('x')
> +    assert fcode(4*I) == "      cmplx(0,4)"
> +    assert fcode(3+4*I) == "      cmplx(3,4)"
> +    assert fcode(3+4*I+x) == "      cmplx(3,4) + x"
> +    assert fcode(I*x) == "      cmplx(0,1)*x"
> +    assert fcode(3+4*I-x) == "      cmplx(3,4) - x"
> +    x = symbols('x', imaginary=True)
> +    assert fcode(5*x) == "      5*x"
> +    assert fcode(I*x) == "      cmplx(0,1)*x"
> +    assert fcode(3+x) == "      3 + x"
> +
> +def test_implicit():
> +    x, y = symbols('xy')
> +    assert fcode(sin(x)) == "      sin(x)"
> +    assert fcode(atan2(x,y)) == "      atan2(x, y)"
> +    assert fcode(conjugate(x)) == "      conjg(x)"
> +
> +def test_not_fortran():
> +    x = symbols('x')
> +    g = Function('g')
> +    assert fcode(gamma(x)) == "C     Not Fortran 77:\nC     gamma(x)\n      
> gamma(x)"
> +    assert fcode(Integral(sin(x))) == "C     Not Fortran 77:\nC     
> Integral(sin(x), x)\n      Integral(sin(x), x)"
> +    assert fcode(g(x)) == "C     Not Fortran 77:\nC     g(x)\n      g(x)"
> +
> +def test_user_functions():
> +    x = symbols('x')
> +    assert fcode(sin(x), user_functions={sin: "zsin"}) == "      zsin(x)"
> +    x = symbols('x')
> +    assert fcode(gamma(x), user_functions={gamma: "mygamma"}) == "      
> mygamma(x)"
> +    g = Function('g')
> +    assert fcode(g(x), user_functions={g: "great"}) == "      great(x)"
> +    n = symbols('n', integer=True)
> +    assert fcode(Factorial(n), user_functions={Factorial: "fct"}) == "      
> fct(n)"
> +
> +def test_assign_to():
> +    x = symbols('x')
> +    assert fcode(sin(x), assign_to="s") == "      s = sin(x)"
> +
> +def test_line_wrapping():
> +    x, y = symbols('xy')
> +    assert fcode(((x+y)**10).expand(), assign_to="var") == (
> +        "      var = 45*x**8*y**2 + 120*x**7*y**3 + 210*x**6*y**4 + 
> 252*x**5*y**5\n"
> +        "     @ + 210*x**4*y**6 + 120*x**3*y**7 + 45*x**2*y**8 + 10*x*y**9 + 
> 10*y\n"
> +        "     @ *x**9 + x**10 + y**10"
> +    )
> +    e = [x**i for i in range(11)]
> +    assert fcode(Add(*e)) == (
> +        "      1 + x + x**2 + x**3 + x**4 + x**5 + x**6 + x**7 + x**8 + x**9 
> + x\n"
> +        "     @ **10"
> +    )
> +
> +def test_fcode_Piecewise():
> +    x = symbols('x')
> +    assert fcode(Piecewise((x,x<1),(x**2,True))) == (
> +        "      if (x < 1) then\n"
> +        "        x\n"
> +        "      else\n"
> +        "        x**2\n"
> +        "      end if"
> +    )
> +    assert fcode(Piecewise((x,x<1),(x**2,True)), assign_to="var") == (
> +        "      if (x < 1) then\n"
> +        "        var = x\n"
> +        "      else\n"
> +        "        var = x**2\n"
> +        "      end if"
> +    )
> +    a = cos(x)/x
> +    b = sin(x)/x
> +    for i in xrange(10):
> +        a = diff(a, x)
> +        b = diff(b, x)
> +    assert fcode(Piecewise((a,x<0),(b,True)), assign_to="weird_name") == (
> +        "      if (x < 0) then\n"
> +        "        weird_name = -cos(x)/x - 1814400*cos(x)/x**9 - 
> 604800*sin(x)/x\n"
> +        "     @ **8 - 5040*cos(x)/x**5 - 720*sin(x)/x**4 + 10*sin(x)/x**2 + 
> 90*\n"
> +        "     @ cos(x)/x**3 + 30240*sin(x)/x**6 + 151200*cos(x)/x**7 + 
> 3628800*\n"
> +        "     @ cos(x)/x**11 + 3628800*sin(x)/x**10\n"
> +        "      else\n"
> +        "        weird_name = -sin(x)/x - 3628800*cos(x)/x**10 - 
> 1814400*sin(x)/x\n"
> +        "     @ **9 - 30240*cos(x)/x**6 - 5040*sin(x)/x**5 - 10*cos(x)/x**2 
> + 90*\n"
> +        "     @ sin(x)/x**3 + 720*cos(x)/x**4 + 151200*sin(x)/x**7 + 
> 604800*cos(x\n"
> +        "     @ )/x**8 + 3628800*sin(x)/x**11\n"
> +        "      end if"
> +    )
> +    assert fcode(Piecewise((x,x<1),(x**2,x>1),(sin(x),True))) == (
> +        "      if (x < 1) then\n"
> +        "        x\n"
> +        "      else if (1 < x) then\n"
> +        "        x**2\n"
> +        "      else\n"
> +        "        sin(x)\n"
> +        "      end if"
> +    )
> +    assert fcode(Piecewise((x,x<1),(x**2,x>1),(sin(x),x>0))) == (
> +        "      if (x < 1) then\n"
> +        "        x\n"
> +        "      else if (1 < x) then\n"
> +        "        x**2\n"
> +        "      else if (0 < x) then\n"
> +        "        sin(x)\n"
> +        "      end if"
> +    )
> +
> +def test_wrap_fortran():
> +    #   
> "########################################################################"
> +    lines = [
> +        "C     This is a long comment on a single line that must be wrapped 
> properly",
> +        "      this = is + a + long + and + nasty + fortran + statement + 
> that * must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + statement +  
> that * must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + statement +   
> that * must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + statement + 
> that*must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + statement +   
> that*must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + statement +    
> that*must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + statement +    
>  that*must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + statement + 
> that**must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + statement +  
> that**must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + statement +   
> that**must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + statement +    
> that**must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + statement +    
>  that**must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + 
> statement(that)/must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran +     
> statement(that)/must + be + wrapped + properly",
> +    ]
> +    wrapped_lines = wrap_fortran(lines)
> +    expected_lines = [
> +        "C     This is a long comment on a single line that must be wrapped",
> +        "C     properly",
> +        "      this = is + a + long + and + nasty + fortran + statement + 
> that *",
> +        "     @ must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + statement +  
> that *",
> +        "     @ must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + statement +   
> that",
> +        "     @ * must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + statement + 
> that*",
> +        "     @ must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + statement +   
> that*",
> +        "     @ must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + statement +    
> that",
> +        "     @ *must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + statement +",
> +        "     @ that*must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + statement + 
> that**",
> +        "     @ must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + statement +  
> that**",
> +        "     @ must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + statement +   
> that",
> +        "     @ **must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + statement +    
> that",
> +        "     @ **must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + statement +",
> +        "     @ that**must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran + 
> statement(that)/",
> +        "     @ must + be + wrapped + properly",
> +        "      this = is + a + long + and + nasty + fortran +     
> statement(that)",
> +        "     @ /must + be + wrapped + properly",
> +    ]
> +    for line in wrapped_lines:
> +        assert len(line) <= 72
> +    for w, e in zip(wrapped_lines, expected_lines):
> +        assert w == e
> +    assert len(wrapped_lines) == len(expected_lines)
> +
> --
> 1.6.3.3

-- 
You received this message because you are subscribed to the Google Groups 
"sympy-patches" group.
To post to this group, send email to sympy-patc...@googlegroups.com.
To unsubscribe from this group, send email to 
sympy-patches+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sympy-patches?hl=en.

Reply via email to