test_fortran.py 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854
  1. from sympy.core.add import Add
  2. from sympy.core.expr import Expr
  3. from sympy.core.function import (Function, Lambda, diff)
  4. from sympy.core.mod import Mod
  5. from sympy.core import (Catalan, EulerGamma, GoldenRatio)
  6. from sympy.core.numbers import (E, Float, I, Integer, Rational, pi)
  7. from sympy.core.relational import Eq
  8. from sympy.core.singleton import S
  9. from sympy.core.symbol import (Dummy, symbols)
  10. from sympy.functions.combinatorial.factorials import factorial
  11. from sympy.functions.elementary.complexes import (conjugate, sign)
  12. from sympy.functions.elementary.exponential import (exp, log)
  13. from sympy.functions.elementary.miscellaneous import sqrt
  14. from sympy.functions.elementary.piecewise import Piecewise
  15. from sympy.functions.elementary.trigonometric import (atan2, cos, sin)
  16. from sympy.functions.special.gamma_functions import gamma
  17. from sympy.integrals.integrals import Integral
  18. from sympy.sets.fancysets import Range
  19. from sympy.codegen import For, Assignment, aug_assign
  20. from sympy.codegen.ast import Declaration, Variable, float32, float64, \
  21. value_const, real, bool_, While, FunctionPrototype, FunctionDefinition, \
  22. integer, Return, Element
  23. from sympy.core.expr import UnevaluatedExpr
  24. from sympy.core.relational import Relational
  25. from sympy.logic.boolalg import And, Or, Not, Equivalent, Xor
  26. from sympy.matrices import Matrix, MatrixSymbol
  27. from sympy.printing.fortran import fcode, FCodePrinter
  28. from sympy.tensor import IndexedBase, Idx
  29. from sympy.tensor.array.expressions import ArraySymbol, ArrayElement
  30. from sympy.utilities.lambdify import implemented_function
  31. from sympy.testing.pytest import raises
  32. def test_UnevaluatedExpr():
  33. p, q, r = symbols("p q r", real=True)
  34. q_r = UnevaluatedExpr(q + r)
  35. expr = abs(exp(p+q_r))
  36. assert fcode(expr, source_format="free") == "exp(p + (q + r))"
  37. x, y, z = symbols("x y z")
  38. y_z = UnevaluatedExpr(y + z)
  39. expr2 = abs(exp(x+y_z))
  40. assert fcode(expr2, human=False)[2].lstrip() == "exp(re(x) + re(y + z))"
  41. assert fcode(expr2, user_functions={"re": "realpart"}).lstrip() == "exp(realpart(x) + realpart(y + z))"
  42. def test_printmethod():
  43. x = symbols('x')
  44. class nint(Function):
  45. def _fcode(self, printer):
  46. return "nint(%s)" % printer._print(self.args[0])
  47. assert fcode(nint(x)) == " nint(x)"
  48. def test_fcode_sign(): #issue 12267
  49. x=symbols('x')
  50. y=symbols('y', integer=True)
  51. z=symbols('z', complex=True)
  52. assert fcode(sign(x), standard=95, source_format='free') == "merge(0d0, dsign(1d0, x), x == 0d0)"
  53. assert fcode(sign(y), standard=95, source_format='free') == "merge(0, isign(1, y), y == 0)"
  54. assert fcode(sign(z), standard=95, source_format='free') == "merge(cmplx(0d0, 0d0), z/abs(z), abs(z) == 0d0)"
  55. raises(NotImplementedError, lambda: fcode(sign(x)))
  56. def test_fcode_Pow():
  57. x, y = symbols('x,y')
  58. n = symbols('n', integer=True)
  59. assert fcode(x**3) == " x**3"
  60. assert fcode(x**(y**3)) == " x**(y**3)"
  61. assert fcode(1/(sin(x)*3.5)**(x - y**x)/(x**2 + y)) == \
  62. " (3.5d0*sin(x))**(-x + y**x)/(x**2 + y)"
  63. assert fcode(sqrt(x)) == ' sqrt(x)'
  64. assert fcode(sqrt(n)) == ' sqrt(dble(n))'
  65. assert fcode(x**0.5) == ' sqrt(x)'
  66. assert fcode(sqrt(x)) == ' sqrt(x)'
  67. assert fcode(sqrt(10)) == ' sqrt(10.0d0)'
  68. assert fcode(x**-1.0) == ' 1d0/x'
  69. assert fcode(x**-2.0, 'y', source_format='free') == 'y = x**(-2.0d0)' # 2823
  70. assert fcode(x**Rational(3, 7)) == ' x**(3.0d0/7.0d0)'
  71. def test_fcode_Rational():
  72. x = symbols('x')
  73. assert fcode(Rational(3, 7)) == " 3.0d0/7.0d0"
  74. assert fcode(Rational(18, 9)) == " 2"
  75. assert fcode(Rational(3, -7)) == " -3.0d0/7.0d0"
  76. assert fcode(Rational(-3, -7)) == " 3.0d0/7.0d0"
  77. assert fcode(x + Rational(3, 7)) == " x + 3.0d0/7.0d0"
  78. assert fcode(Rational(3, 7)*x) == " (3.0d0/7.0d0)*x"
  79. def test_fcode_Integer():
  80. assert fcode(Integer(67)) == " 67"
  81. assert fcode(Integer(-1)) == " -1"
  82. def test_fcode_Float():
  83. assert fcode(Float(42.0)) == " 42.0000000000000d0"
  84. assert fcode(Float(-1e20)) == " -1.00000000000000d+20"
  85. def test_fcode_functions():
  86. x, y = symbols('x,y')
  87. assert fcode(sin(x) ** cos(y)) == " sin(x)**cos(y)"
  88. raises(NotImplementedError, lambda: fcode(Mod(x, y), standard=66))
  89. raises(NotImplementedError, lambda: fcode(x % y, standard=66))
  90. raises(NotImplementedError, lambda: fcode(Mod(x, y), standard=77))
  91. raises(NotImplementedError, lambda: fcode(x % y, standard=77))
  92. for standard in [90, 95, 2003, 2008]:
  93. assert fcode(Mod(x, y), standard=standard) == " modulo(x, y)"
  94. assert fcode(x % y, standard=standard) == " modulo(x, y)"
  95. def test_case():
  96. ob = FCodePrinter()
  97. x,x_,x__,y,X,X_,Y = symbols('x,x_,x__,y,X,X_,Y')
  98. assert fcode(exp(x_) + sin(x*y) + cos(X*Y)) == \
  99. ' exp(x_) + sin(x*y) + cos(X__*Y_)'
  100. assert fcode(exp(x__) + 2*x*Y*X_**Rational(7, 2)) == \
  101. ' 2*X_**(7.0d0/2.0d0)*Y*x + exp(x__)'
  102. assert fcode(exp(x_) + sin(x*y) + cos(X*Y), name_mangling=False) == \
  103. ' exp(x_) + sin(x*y) + cos(X*Y)'
  104. assert fcode(x - cos(X), name_mangling=False) == ' x - cos(X)'
  105. assert ob.doprint(X*sin(x) + x_, assign_to='me') == ' me = X*sin(x_) + x__'
  106. assert ob.doprint(X*sin(x), assign_to='mu') == ' mu = X*sin(x_)'
  107. assert ob.doprint(x_, assign_to='ad') == ' ad = x__'
  108. n, m = symbols('n,m', integer=True)
  109. A = IndexedBase('A')
  110. x = IndexedBase('x')
  111. y = IndexedBase('y')
  112. i = Idx('i', m)
  113. I = Idx('I', n)
  114. assert fcode(A[i, I]*x[I], assign_to=y[i], source_format='free') == (
  115. "do i = 1, m\n"
  116. " y(i) = 0\n"
  117. "end do\n"
  118. "do i = 1, m\n"
  119. " do I_ = 1, n\n"
  120. " y(i) = A(i, I_)*x(I_) + y(i)\n"
  121. " end do\n"
  122. "end do" )
  123. #issue 6814
  124. def test_fcode_functions_with_integers():
  125. x= symbols('x')
  126. log10_17 = log(10).evalf(17)
  127. loglog10_17 = '0.8340324452479558d0'
  128. assert fcode(x * log(10)) == " x*%sd0" % log10_17
  129. assert fcode(x * log(10)) == " x*%sd0" % log10_17
  130. assert fcode(x * log(S(10))) == " x*%sd0" % log10_17
  131. assert fcode(log(S(10))) == " %sd0" % log10_17
  132. assert fcode(exp(10)) == " %sd0" % exp(10).evalf(17)
  133. assert fcode(x * log(log(10))) == " x*%s" % loglog10_17
  134. assert fcode(x * log(log(S(10)))) == " x*%s" % loglog10_17
  135. def test_fcode_NumberSymbol():
  136. prec = 17
  137. p = FCodePrinter()
  138. assert fcode(Catalan) == ' parameter (Catalan = %sd0)\n Catalan' % Catalan.evalf(prec)
  139. assert fcode(EulerGamma) == ' parameter (EulerGamma = %sd0)\n EulerGamma' % EulerGamma.evalf(prec)
  140. assert fcode(E) == ' parameter (E = %sd0)\n E' % E.evalf(prec)
  141. assert fcode(GoldenRatio) == ' parameter (GoldenRatio = %sd0)\n GoldenRatio' % GoldenRatio.evalf(prec)
  142. assert fcode(pi) == ' parameter (pi = %sd0)\n pi' % pi.evalf(prec)
  143. assert fcode(
  144. pi, precision=5) == ' parameter (pi = %sd0)\n pi' % pi.evalf(5)
  145. assert fcode(Catalan, human=False) == ({
  146. (Catalan, p._print(Catalan.evalf(prec)))}, set(), ' Catalan')
  147. assert fcode(EulerGamma, human=False) == ({(EulerGamma, p._print(
  148. EulerGamma.evalf(prec)))}, set(), ' EulerGamma')
  149. assert fcode(E, human=False) == (
  150. {(E, p._print(E.evalf(prec)))}, set(), ' E')
  151. assert fcode(GoldenRatio, human=False) == ({(GoldenRatio, p._print(
  152. GoldenRatio.evalf(prec)))}, set(), ' GoldenRatio')
  153. assert fcode(pi, human=False) == (
  154. {(pi, p._print(pi.evalf(prec)))}, set(), ' pi')
  155. assert fcode(pi, precision=5, human=False) == (
  156. {(pi, p._print(pi.evalf(5)))}, set(), ' pi')
  157. def test_fcode_complex():
  158. assert fcode(I) == " cmplx(0,1)"
  159. x = symbols('x')
  160. assert fcode(4*I) == " cmplx(0,4)"
  161. assert fcode(3 + 4*I) == " cmplx(3,4)"
  162. assert fcode(3 + 4*I + x) == " cmplx(3,4) + x"
  163. assert fcode(I*x) == " cmplx(0,1)*x"
  164. assert fcode(3 + 4*I - x) == " cmplx(3,4) - x"
  165. x = symbols('x', imaginary=True)
  166. assert fcode(5*x) == " 5*x"
  167. assert fcode(I*x) == " cmplx(0,1)*x"
  168. assert fcode(3 + x) == " x + 3"
  169. def test_implicit():
  170. x, y = symbols('x,y')
  171. assert fcode(sin(x)) == " sin(x)"
  172. assert fcode(atan2(x, y)) == " atan2(x, y)"
  173. assert fcode(conjugate(x)) == " conjg(x)"
  174. def test_not_fortran():
  175. x = symbols('x')
  176. g = Function('g')
  177. with raises(NotImplementedError):
  178. fcode(gamma(x))
  179. assert fcode(Integral(sin(x)), strict=False) == "C Not supported in Fortran:\nC Integral\n Integral(sin(x), x)"
  180. with raises(NotImplementedError):
  181. fcode(g(x))
  182. def test_user_functions():
  183. x = symbols('x')
  184. assert fcode(sin(x), user_functions={"sin": "zsin"}) == " zsin(x)"
  185. x = symbols('x')
  186. assert fcode(
  187. gamma(x), user_functions={"gamma": "mygamma"}) == " mygamma(x)"
  188. g = Function('g')
  189. assert fcode(g(x), user_functions={"g": "great"}) == " great(x)"
  190. n = symbols('n', integer=True)
  191. assert fcode(
  192. factorial(n), user_functions={"factorial": "fct"}) == " fct(n)"
  193. def test_inline_function():
  194. x = symbols('x')
  195. g = implemented_function('g', Lambda(x, 2*x))
  196. assert fcode(g(x)) == " 2*x"
  197. g = implemented_function('g', Lambda(x, 2*pi/x))
  198. assert fcode(g(x)) == (
  199. " parameter (pi = %sd0)\n"
  200. " 2*pi/x"
  201. ) % pi.evalf(17)
  202. A = IndexedBase('A')
  203. i = Idx('i', symbols('n', integer=True))
  204. g = implemented_function('g', Lambda(x, x*(1 + x)*(2 + x)))
  205. assert fcode(g(A[i]), assign_to=A[i]) == (
  206. " do i = 1, n\n"
  207. " A(i) = (A(i) + 1)*(A(i) + 2)*A(i)\n"
  208. " end do"
  209. )
  210. def test_assign_to():
  211. x = symbols('x')
  212. assert fcode(sin(x), assign_to="s") == " s = sin(x)"
  213. def test_line_wrapping():
  214. x, y = symbols('x,y')
  215. assert fcode(((x + y)**10).expand(), assign_to="var") == (
  216. " var = x**10 + 10*x**9*y + 45*x**8*y**2 + 120*x**7*y**3 + 210*x**6*\n"
  217. " @ y**4 + 252*x**5*y**5 + 210*x**4*y**6 + 120*x**3*y**7 + 45*x**2*y\n"
  218. " @ **8 + 10*x*y**9 + y**10"
  219. )
  220. e = [x**i for i in range(11)]
  221. assert fcode(Add(*e)) == (
  222. " x**10 + x**9 + x**8 + x**7 + x**6 + x**5 + x**4 + x**3 + x**2 + x\n"
  223. " @ + 1"
  224. )
  225. def test_fcode_precedence():
  226. x, y = symbols("x y")
  227. assert fcode(And(x < y, y < x + 1), source_format="free") == \
  228. "x < y .and. y < x + 1"
  229. assert fcode(Or(x < y, y < x + 1), source_format="free") == \
  230. "x < y .or. y < x + 1"
  231. assert fcode(Xor(x < y, y < x + 1, evaluate=False),
  232. source_format="free") == "x < y .neqv. y < x + 1"
  233. assert fcode(Equivalent(x < y, y < x + 1), source_format="free") == \
  234. "x < y .eqv. y < x + 1"
  235. def test_fcode_Logical():
  236. x, y, z = symbols("x y z")
  237. # unary Not
  238. assert fcode(Not(x), source_format="free") == ".not. x"
  239. # binary And
  240. assert fcode(And(x, y), source_format="free") == "x .and. y"
  241. assert fcode(And(x, Not(y)), source_format="free") == "x .and. .not. y"
  242. assert fcode(And(Not(x), y), source_format="free") == "y .and. .not. x"
  243. assert fcode(And(Not(x), Not(y)), source_format="free") == \
  244. ".not. x .and. .not. y"
  245. assert fcode(Not(And(x, y), evaluate=False), source_format="free") == \
  246. ".not. (x .and. y)"
  247. # binary Or
  248. assert fcode(Or(x, y), source_format="free") == "x .or. y"
  249. assert fcode(Or(x, Not(y)), source_format="free") == "x .or. .not. y"
  250. assert fcode(Or(Not(x), y), source_format="free") == "y .or. .not. x"
  251. assert fcode(Or(Not(x), Not(y)), source_format="free") == \
  252. ".not. x .or. .not. y"
  253. assert fcode(Not(Or(x, y), evaluate=False), source_format="free") == \
  254. ".not. (x .or. y)"
  255. # mixed And/Or
  256. assert fcode(And(Or(y, z), x), source_format="free") == "x .and. (y .or. z)"
  257. assert fcode(And(Or(z, x), y), source_format="free") == "y .and. (x .or. z)"
  258. assert fcode(And(Or(x, y), z), source_format="free") == "z .and. (x .or. y)"
  259. assert fcode(Or(And(y, z), x), source_format="free") == "x .or. y .and. z"
  260. assert fcode(Or(And(z, x), y), source_format="free") == "y .or. x .and. z"
  261. assert fcode(Or(And(x, y), z), source_format="free") == "z .or. x .and. y"
  262. # trinary And
  263. assert fcode(And(x, y, z), source_format="free") == "x .and. y .and. z"
  264. assert fcode(And(x, y, Not(z)), source_format="free") == \
  265. "x .and. y .and. .not. z"
  266. assert fcode(And(x, Not(y), z), source_format="free") == \
  267. "x .and. z .and. .not. y"
  268. assert fcode(And(Not(x), y, z), source_format="free") == \
  269. "y .and. z .and. .not. x"
  270. assert fcode(Not(And(x, y, z), evaluate=False), source_format="free") == \
  271. ".not. (x .and. y .and. z)"
  272. # trinary Or
  273. assert fcode(Or(x, y, z), source_format="free") == "x .or. y .or. z"
  274. assert fcode(Or(x, y, Not(z)), source_format="free") == \
  275. "x .or. y .or. .not. z"
  276. assert fcode(Or(x, Not(y), z), source_format="free") == \
  277. "x .or. z .or. .not. y"
  278. assert fcode(Or(Not(x), y, z), source_format="free") == \
  279. "y .or. z .or. .not. x"
  280. assert fcode(Not(Or(x, y, z), evaluate=False), source_format="free") == \
  281. ".not. (x .or. y .or. z)"
  282. def test_fcode_Xlogical():
  283. x, y, z = symbols("x y z")
  284. # binary Xor
  285. assert fcode(Xor(x, y, evaluate=False), source_format="free") == \
  286. "x .neqv. y"
  287. assert fcode(Xor(x, Not(y), evaluate=False), source_format="free") == \
  288. "x .neqv. .not. y"
  289. assert fcode(Xor(Not(x), y, evaluate=False), source_format="free") == \
  290. "y .neqv. .not. x"
  291. assert fcode(Xor(Not(x), Not(y), evaluate=False),
  292. source_format="free") == ".not. x .neqv. .not. y"
  293. assert fcode(Not(Xor(x, y, evaluate=False), evaluate=False),
  294. source_format="free") == ".not. (x .neqv. y)"
  295. # binary Equivalent
  296. assert fcode(Equivalent(x, y), source_format="free") == "x .eqv. y"
  297. assert fcode(Equivalent(x, Not(y)), source_format="free") == \
  298. "x .eqv. .not. y"
  299. assert fcode(Equivalent(Not(x), y), source_format="free") == \
  300. "y .eqv. .not. x"
  301. assert fcode(Equivalent(Not(x), Not(y)), source_format="free") == \
  302. ".not. x .eqv. .not. y"
  303. assert fcode(Not(Equivalent(x, y), evaluate=False),
  304. source_format="free") == ".not. (x .eqv. y)"
  305. # mixed And/Equivalent
  306. assert fcode(Equivalent(And(y, z), x), source_format="free") == \
  307. "x .eqv. y .and. z"
  308. assert fcode(Equivalent(And(z, x), y), source_format="free") == \
  309. "y .eqv. x .and. z"
  310. assert fcode(Equivalent(And(x, y), z), source_format="free") == \
  311. "z .eqv. x .and. y"
  312. assert fcode(And(Equivalent(y, z), x), source_format="free") == \
  313. "x .and. (y .eqv. z)"
  314. assert fcode(And(Equivalent(z, x), y), source_format="free") == \
  315. "y .and. (x .eqv. z)"
  316. assert fcode(And(Equivalent(x, y), z), source_format="free") == \
  317. "z .and. (x .eqv. y)"
  318. # mixed Or/Equivalent
  319. assert fcode(Equivalent(Or(y, z), x), source_format="free") == \
  320. "x .eqv. y .or. z"
  321. assert fcode(Equivalent(Or(z, x), y), source_format="free") == \
  322. "y .eqv. x .or. z"
  323. assert fcode(Equivalent(Or(x, y), z), source_format="free") == \
  324. "z .eqv. x .or. y"
  325. assert fcode(Or(Equivalent(y, z), x), source_format="free") == \
  326. "x .or. (y .eqv. z)"
  327. assert fcode(Or(Equivalent(z, x), y), source_format="free") == \
  328. "y .or. (x .eqv. z)"
  329. assert fcode(Or(Equivalent(x, y), z), source_format="free") == \
  330. "z .or. (x .eqv. y)"
  331. # mixed Xor/Equivalent
  332. assert fcode(Equivalent(Xor(y, z, evaluate=False), x),
  333. source_format="free") == "x .eqv. (y .neqv. z)"
  334. assert fcode(Equivalent(Xor(z, x, evaluate=False), y),
  335. source_format="free") == "y .eqv. (x .neqv. z)"
  336. assert fcode(Equivalent(Xor(x, y, evaluate=False), z),
  337. source_format="free") == "z .eqv. (x .neqv. y)"
  338. assert fcode(Xor(Equivalent(y, z), x, evaluate=False),
  339. source_format="free") == "x .neqv. (y .eqv. z)"
  340. assert fcode(Xor(Equivalent(z, x), y, evaluate=False),
  341. source_format="free") == "y .neqv. (x .eqv. z)"
  342. assert fcode(Xor(Equivalent(x, y), z, evaluate=False),
  343. source_format="free") == "z .neqv. (x .eqv. y)"
  344. # mixed And/Xor
  345. assert fcode(Xor(And(y, z), x, evaluate=False), source_format="free") == \
  346. "x .neqv. y .and. z"
  347. assert fcode(Xor(And(z, x), y, evaluate=False), source_format="free") == \
  348. "y .neqv. x .and. z"
  349. assert fcode(Xor(And(x, y), z, evaluate=False), source_format="free") == \
  350. "z .neqv. x .and. y"
  351. assert fcode(And(Xor(y, z, evaluate=False), x), source_format="free") == \
  352. "x .and. (y .neqv. z)"
  353. assert fcode(And(Xor(z, x, evaluate=False), y), source_format="free") == \
  354. "y .and. (x .neqv. z)"
  355. assert fcode(And(Xor(x, y, evaluate=False), z), source_format="free") == \
  356. "z .and. (x .neqv. y)"
  357. # mixed Or/Xor
  358. assert fcode(Xor(Or(y, z), x, evaluate=False), source_format="free") == \
  359. "x .neqv. y .or. z"
  360. assert fcode(Xor(Or(z, x), y, evaluate=False), source_format="free") == \
  361. "y .neqv. x .or. z"
  362. assert fcode(Xor(Or(x, y), z, evaluate=False), source_format="free") == \
  363. "z .neqv. x .or. y"
  364. assert fcode(Or(Xor(y, z, evaluate=False), x), source_format="free") == \
  365. "x .or. (y .neqv. z)"
  366. assert fcode(Or(Xor(z, x, evaluate=False), y), source_format="free") == \
  367. "y .or. (x .neqv. z)"
  368. assert fcode(Or(Xor(x, y, evaluate=False), z), source_format="free") == \
  369. "z .or. (x .neqv. y)"
  370. # trinary Xor
  371. assert fcode(Xor(x, y, z, evaluate=False), source_format="free") == \
  372. "x .neqv. y .neqv. z"
  373. assert fcode(Xor(x, y, Not(z), evaluate=False), source_format="free") == \
  374. "x .neqv. y .neqv. .not. z"
  375. assert fcode(Xor(x, Not(y), z, evaluate=False), source_format="free") == \
  376. "x .neqv. z .neqv. .not. y"
  377. assert fcode(Xor(Not(x), y, z, evaluate=False), source_format="free") == \
  378. "y .neqv. z .neqv. .not. x"
  379. def test_fcode_Relational():
  380. x, y = symbols("x y")
  381. assert fcode(Relational(x, y, "=="), source_format="free") == "x == y"
  382. assert fcode(Relational(x, y, "!="), source_format="free") == "x /= y"
  383. assert fcode(Relational(x, y, ">="), source_format="free") == "x >= y"
  384. assert fcode(Relational(x, y, "<="), source_format="free") == "x <= y"
  385. assert fcode(Relational(x, y, ">"), source_format="free") == "x > y"
  386. assert fcode(Relational(x, y, "<"), source_format="free") == "x < y"
  387. def test_fcode_Piecewise():
  388. x = symbols('x')
  389. expr = Piecewise((x, x < 1), (x**2, True))
  390. # Check that inline conditional (merge) fails if standard isn't 95+
  391. raises(NotImplementedError, lambda: fcode(expr))
  392. code = fcode(expr, standard=95)
  393. expected = " merge(x, x**2, x < 1)"
  394. assert code == expected
  395. assert fcode(Piecewise((x, x < 1), (x**2, True)), assign_to="var") == (
  396. " if (x < 1) then\n"
  397. " var = x\n"
  398. " else\n"
  399. " var = x**2\n"
  400. " end if"
  401. )
  402. a = cos(x)/x
  403. b = sin(x)/x
  404. for i in range(10):
  405. a = diff(a, x)
  406. b = diff(b, x)
  407. expected = (
  408. " if (x < 0) then\n"
  409. " weird_name = -cos(x)/x + 10*sin(x)/x**2 + 90*cos(x)/x**3 - 720*\n"
  410. " @ sin(x)/x**4 - 5040*cos(x)/x**5 + 30240*sin(x)/x**6 + 151200*cos(x\n"
  411. " @ )/x**7 - 604800*sin(x)/x**8 - 1814400*cos(x)/x**9 + 3628800*sin(x\n"
  412. " @ )/x**10 + 3628800*cos(x)/x**11\n"
  413. " else\n"
  414. " weird_name = -sin(x)/x - 10*cos(x)/x**2 + 90*sin(x)/x**3 + 720*\n"
  415. " @ cos(x)/x**4 - 5040*sin(x)/x**5 - 30240*cos(x)/x**6 + 151200*sin(x\n"
  416. " @ )/x**7 + 604800*cos(x)/x**8 - 1814400*sin(x)/x**9 - 3628800*cos(x\n"
  417. " @ )/x**10 + 3628800*sin(x)/x**11\n"
  418. " end if"
  419. )
  420. code = fcode(Piecewise((a, x < 0), (b, True)), assign_to="weird_name")
  421. assert code == expected
  422. code = fcode(Piecewise((x, x < 1), (x**2, x > 1), (sin(x), True)), standard=95)
  423. expected = " merge(x, merge(x**2, sin(x), x > 1), x < 1)"
  424. assert code == expected
  425. # Check that Piecewise without a True (default) condition error
  426. expr = Piecewise((x, x < 1), (x**2, x > 1), (sin(x), x > 0))
  427. raises(ValueError, lambda: fcode(expr))
  428. def test_wrap_fortran():
  429. # "########################################################################"
  430. printer = FCodePrinter()
  431. lines = [
  432. "C This is a long comment on a single line that must be wrapped properly to produce nice output",
  433. " this = is + a + long + and + nasty + fortran + statement + that * must + be + wrapped + properly",
  434. " this = is + a + long + and + nasty + fortran + statement + that * must + be + wrapped + properly",
  435. " this = is + a + long + and + nasty + fortran + statement + that * must + be + wrapped + properly",
  436. " this = is + a + long + and + nasty + fortran + statement + that*must + be + wrapped + properly",
  437. " this = is + a + long + and + nasty + fortran + statement + that*must + be + wrapped + properly",
  438. " this = is + a + long + and + nasty + fortran + statement + that*must + be + wrapped + properly",
  439. " this = is + a + long + and + nasty + fortran + statement + that*must + be + wrapped + properly",
  440. " this = is + a + long + and + nasty + fortran + statement + that**must + be + wrapped + properly",
  441. " this = is + a + long + and + nasty + fortran + statement + that**must + be + wrapped + properly",
  442. " this = is + a + long + and + nasty + fortran + statement + that**must + be + wrapped + properly",
  443. " this = is + a + long + and + nasty + fortran + statement + that**must + be + wrapped + properly",
  444. " this = is + a + long + and + nasty + fortran + statement + that**must + be + wrapped + properly",
  445. " this = is + a + long + and + nasty + fortran + statement(that)/must + be + wrapped + properly",
  446. " this = is + a + long + and + nasty + fortran + statement(that)/must + be + wrapped + properly",
  447. ]
  448. wrapped_lines = printer._wrap_fortran(lines)
  449. expected_lines = [
  450. "C This is a long comment on a single line that must be wrapped",
  451. "C properly to produce nice output",
  452. " this = is + a + long + and + nasty + fortran + statement + that *",
  453. " @ must + be + wrapped + properly",
  454. " this = is + a + long + and + nasty + fortran + statement + that *",
  455. " @ must + be + wrapped + properly",
  456. " this = is + a + long + and + nasty + fortran + statement + that",
  457. " @ * must + be + wrapped + properly",
  458. " this = is + a + long + and + nasty + fortran + statement + that*",
  459. " @ must + be + wrapped + properly",
  460. " this = is + a + long + and + nasty + fortran + statement + that*",
  461. " @ must + be + wrapped + properly",
  462. " this = is + a + long + and + nasty + fortran + statement + that",
  463. " @ *must + be + wrapped + properly",
  464. " this = is + a + long + and + nasty + fortran + statement +",
  465. " @ that*must + be + wrapped + properly",
  466. " this = is + a + long + and + nasty + fortran + statement + that**",
  467. " @ must + be + wrapped + properly",
  468. " this = is + a + long + and + nasty + fortran + statement + that**",
  469. " @ must + be + wrapped + properly",
  470. " this = is + a + long + and + nasty + fortran + statement + that",
  471. " @ **must + be + wrapped + properly",
  472. " this = is + a + long + and + nasty + fortran + statement + that",
  473. " @ **must + be + wrapped + properly",
  474. " this = is + a + long + and + nasty + fortran + statement +",
  475. " @ that**must + be + wrapped + properly",
  476. " this = is + a + long + and + nasty + fortran + statement(that)/",
  477. " @ must + be + wrapped + properly",
  478. " this = is + a + long + and + nasty + fortran + statement(that)",
  479. " @ /must + be + wrapped + properly",
  480. ]
  481. for line in wrapped_lines:
  482. assert len(line) <= 72
  483. for w, e in zip(wrapped_lines, expected_lines):
  484. assert w == e
  485. assert len(wrapped_lines) == len(expected_lines)
  486. def test_wrap_fortran_keep_d0():
  487. printer = FCodePrinter()
  488. lines = [
  489. ' this_variable_is_very_long_because_we_try_to_test_line_break=1.0d0',
  490. ' this_variable_is_very_long_because_we_try_to_test_line_break =1.0d0',
  491. ' this_variable_is_very_long_because_we_try_to_test_line_break = 1.0d0',
  492. ' this_variable_is_very_long_because_we_try_to_test_line_break = 1.0d0',
  493. ' this_variable_is_very_long_because_we_try_to_test_line_break = 1.0d0',
  494. ' this_variable_is_very_long_because_we_try_to_test_line_break = 10.0d0'
  495. ]
  496. expected = [
  497. ' this_variable_is_very_long_because_we_try_to_test_line_break=1.0d0',
  498. ' this_variable_is_very_long_because_we_try_to_test_line_break =',
  499. ' @ 1.0d0',
  500. ' this_variable_is_very_long_because_we_try_to_test_line_break =',
  501. ' @ 1.0d0',
  502. ' this_variable_is_very_long_because_we_try_to_test_line_break =',
  503. ' @ 1.0d0',
  504. ' this_variable_is_very_long_because_we_try_to_test_line_break =',
  505. ' @ 1.0d0',
  506. ' this_variable_is_very_long_because_we_try_to_test_line_break =',
  507. ' @ 10.0d0'
  508. ]
  509. assert printer._wrap_fortran(lines) == expected
  510. def test_settings():
  511. raises(TypeError, lambda: fcode(S(4), method="garbage"))
  512. def test_free_form_code_line():
  513. x, y = symbols('x,y')
  514. assert fcode(cos(x) + sin(y), source_format='free') == "sin(y) + cos(x)"
  515. def test_free_form_continuation_line():
  516. x, y = symbols('x,y')
  517. result = fcode(((cos(x) + sin(y))**(7)).expand(), source_format='free')
  518. expected = (
  519. 'sin(y)**7 + 7*sin(y)**6*cos(x) + 21*sin(y)**5*cos(x)**2 + 35*sin(y)**4* &\n'
  520. ' cos(x)**3 + 35*sin(y)**3*cos(x)**4 + 21*sin(y)**2*cos(x)**5 + 7* &\n'
  521. ' sin(y)*cos(x)**6 + cos(x)**7'
  522. )
  523. assert result == expected
  524. def test_free_form_comment_line():
  525. printer = FCodePrinter({'source_format': 'free'})
  526. lines = [ "! This is a long comment on a single line that must be wrapped properly to produce nice output"]
  527. expected = [
  528. '! This is a long comment on a single line that must be wrapped properly',
  529. '! to produce nice output']
  530. assert printer._wrap_fortran(lines) == expected
  531. def test_loops():
  532. n, m = symbols('n,m', integer=True)
  533. A = IndexedBase('A')
  534. x = IndexedBase('x')
  535. y = IndexedBase('y')
  536. i = Idx('i', m)
  537. j = Idx('j', n)
  538. expected = (
  539. 'do i = 1, m\n'
  540. ' y(i) = 0\n'
  541. 'end do\n'
  542. 'do i = 1, m\n'
  543. ' do j = 1, n\n'
  544. ' y(i) = %(rhs)s\n'
  545. ' end do\n'
  546. 'end do'
  547. )
  548. code = fcode(A[i, j]*x[j], assign_to=y[i], source_format='free')
  549. assert (code == expected % {'rhs': 'y(i) + A(i, j)*x(j)'} or
  550. code == expected % {'rhs': 'y(i) + x(j)*A(i, j)'} or
  551. code == expected % {'rhs': 'x(j)*A(i, j) + y(i)'} or
  552. code == expected % {'rhs': 'A(i, j)*x(j) + y(i)'})
  553. def test_dummy_loops():
  554. i, m = symbols('i m', integer=True, cls=Dummy)
  555. x = IndexedBase('x')
  556. y = IndexedBase('y')
  557. i = Idx(i, m)
  558. expected = (
  559. 'do i_%(icount)i = 1, m_%(mcount)i\n'
  560. ' y(i_%(icount)i) = x(i_%(icount)i)\n'
  561. 'end do'
  562. ) % {'icount': i.label.dummy_index, 'mcount': m.dummy_index}
  563. code = fcode(x[i], assign_to=y[i], source_format='free')
  564. assert code == expected
  565. def test_fcode_Indexed_without_looking_for_contraction():
  566. len_y = 5
  567. y = IndexedBase('y', shape=(len_y,))
  568. x = IndexedBase('x', shape=(len_y,))
  569. Dy = IndexedBase('Dy', shape=(len_y-1,))
  570. i = Idx('i', len_y-1)
  571. e=Eq(Dy[i], (y[i+1]-y[i])/(x[i+1]-x[i]))
  572. code0 = fcode(e.rhs, assign_to=e.lhs, contract=False)
  573. assert code0.endswith('Dy(i) = (y(i + 1) - y(i))/(x(i + 1) - x(i))')
  574. def test_element_like_objects():
  575. len_y = 5
  576. y = ArraySymbol('y', shape=(len_y,))
  577. x = ArraySymbol('x', shape=(len_y,))
  578. Dy = ArraySymbol('Dy', shape=(len_y-1,))
  579. i = Idx('i', len_y-1)
  580. e=Eq(Dy[i], (y[i+1]-y[i])/(x[i+1]-x[i]))
  581. code0 = fcode(Assignment(e.lhs, e.rhs))
  582. assert code0.endswith('Dy(i) = (y(i + 1) - y(i))/(x(i + 1) - x(i))')
  583. class ElementExpr(Element, Expr):
  584. pass
  585. e = e.subs((a, ElementExpr(a.name, a.indices)) for a in e.atoms(ArrayElement) )
  586. e=Eq(Dy[i], (y[i+1]-y[i])/(x[i+1]-x[i]))
  587. code0 = fcode(Assignment(e.lhs, e.rhs))
  588. assert code0.endswith('Dy(i) = (y(i + 1) - y(i))/(x(i + 1) - x(i))')
  589. def test_derived_classes():
  590. class MyFancyFCodePrinter(FCodePrinter):
  591. _default_settings = FCodePrinter._default_settings.copy()
  592. printer = MyFancyFCodePrinter()
  593. x = symbols('x')
  594. assert printer.doprint(sin(x), "bork") == " bork = sin(x)"
  595. def test_indent():
  596. codelines = (
  597. 'subroutine test(a)\n'
  598. 'integer :: a, i, j\n'
  599. '\n'
  600. 'do\n'
  601. 'do \n'
  602. 'do j = 1, 5\n'
  603. 'if (a>b) then\n'
  604. 'if(b>0) then\n'
  605. 'a = 3\n'
  606. 'donot_indent_me = 2\n'
  607. 'do_not_indent_me_either = 2\n'
  608. 'ifIam_indented_something_went_wrong = 2\n'
  609. 'if_I_am_indented_something_went_wrong = 2\n'
  610. 'end should not be unindented here\n'
  611. 'end if\n'
  612. 'endif\n'
  613. 'end do\n'
  614. 'end do\n'
  615. 'enddo\n'
  616. 'end subroutine\n'
  617. '\n'
  618. 'subroutine test2(a)\n'
  619. 'integer :: a\n'
  620. 'do\n'
  621. 'a = a + 1\n'
  622. 'end do \n'
  623. 'end subroutine\n'
  624. )
  625. expected = (
  626. 'subroutine test(a)\n'
  627. 'integer :: a, i, j\n'
  628. '\n'
  629. 'do\n'
  630. ' do \n'
  631. ' do j = 1, 5\n'
  632. ' if (a>b) then\n'
  633. ' if(b>0) then\n'
  634. ' a = 3\n'
  635. ' donot_indent_me = 2\n'
  636. ' do_not_indent_me_either = 2\n'
  637. ' ifIam_indented_something_went_wrong = 2\n'
  638. ' if_I_am_indented_something_went_wrong = 2\n'
  639. ' end should not be unindented here\n'
  640. ' end if\n'
  641. ' endif\n'
  642. ' end do\n'
  643. ' end do\n'
  644. 'enddo\n'
  645. 'end subroutine\n'
  646. '\n'
  647. 'subroutine test2(a)\n'
  648. 'integer :: a\n'
  649. 'do\n'
  650. ' a = a + 1\n'
  651. 'end do \n'
  652. 'end subroutine\n'
  653. )
  654. p = FCodePrinter({'source_format': 'free'})
  655. result = p.indent_code(codelines)
  656. assert result == expected
  657. def test_Matrix_printing():
  658. x, y, z = symbols('x,y,z')
  659. # Test returning a Matrix
  660. mat = Matrix([x*y, Piecewise((2 + x, y>0), (y, True)), sin(z)])
  661. A = MatrixSymbol('A', 3, 1)
  662. assert fcode(mat, A) == (
  663. " A(1, 1) = x*y\n"
  664. " if (y > 0) then\n"
  665. " A(2, 1) = x + 2\n"
  666. " else\n"
  667. " A(2, 1) = y\n"
  668. " end if\n"
  669. " A(3, 1) = sin(z)")
  670. # Test using MatrixElements in expressions
  671. expr = Piecewise((2*A[2, 0], x > 0), (A[2, 0], True)) + sin(A[1, 0]) + A[0, 0]
  672. assert fcode(expr, standard=95) == (
  673. " merge(2*A(3, 1), A(3, 1), x > 0) + sin(A(2, 1)) + A(1, 1)")
  674. # Test using MatrixElements in a Matrix
  675. q = MatrixSymbol('q', 5, 1)
  676. M = MatrixSymbol('M', 3, 3)
  677. m = Matrix([[sin(q[1,0]), 0, cos(q[2,0])],
  678. [q[1,0] + q[2,0], q[3, 0], 5],
  679. [2*q[4, 0]/q[1,0], sqrt(q[0,0]) + 4, 0]])
  680. assert fcode(m, M) == (
  681. " M(1, 1) = sin(q(2, 1))\n"
  682. " M(2, 1) = q(2, 1) + q(3, 1)\n"
  683. " M(3, 1) = 2*q(5, 1)/q(2, 1)\n"
  684. " M(1, 2) = 0\n"
  685. " M(2, 2) = q(4, 1)\n"
  686. " M(3, 2) = sqrt(q(1, 1)) + 4\n"
  687. " M(1, 3) = cos(q(3, 1))\n"
  688. " M(2, 3) = 5\n"
  689. " M(3, 3) = 0")
  690. def test_fcode_For():
  691. x, y = symbols('x y')
  692. f = For(x, Range(0, 10, 2), [Assignment(y, x * y)])
  693. sol = fcode(f)
  694. assert sol == (" do x = 0, 9, 2\n"
  695. " y = x*y\n"
  696. " end do")
  697. def test_fcode_Declaration():
  698. def check(expr, ref, **kwargs):
  699. assert fcode(expr, standard=95, source_format='free', **kwargs) == ref
  700. i = symbols('i', integer=True)
  701. var1 = Variable.deduced(i)
  702. dcl1 = Declaration(var1)
  703. check(dcl1, "integer*4 :: i")
  704. x, y = symbols('x y')
  705. var2 = Variable(x, float32, value=42, attrs={value_const})
  706. dcl2b = Declaration(var2)
  707. check(dcl2b, 'real*4, parameter :: x = 42')
  708. var3 = Variable(y, type=bool_)
  709. dcl3 = Declaration(var3)
  710. check(dcl3, 'logical :: y')
  711. check(float32, "real*4")
  712. check(float64, "real*8")
  713. check(real, "real*4", type_aliases={real: float32})
  714. check(real, "real*8", type_aliases={real: float64})
  715. def test_MatrixElement_printing():
  716. # test cases for issue #11821
  717. A = MatrixSymbol("A", 1, 3)
  718. B = MatrixSymbol("B", 1, 3)
  719. C = MatrixSymbol("C", 1, 3)
  720. assert(fcode(A[0, 0]) == " A(1, 1)")
  721. assert(fcode(3 * A[0, 0]) == " 3*A(1, 1)")
  722. F = C[0, 0].subs(C, A - B)
  723. assert(fcode(F) == " (A - B)(1, 1)")
  724. def test_aug_assign():
  725. x = symbols('x')
  726. assert fcode(aug_assign(x, '+', 1), source_format='free') == 'x = x + 1'
  727. def test_While():
  728. x = symbols('x')
  729. assert fcode(While(abs(x) > 1, [aug_assign(x, '-', 1)]), source_format='free') == (
  730. 'do while (abs(x) > 1)\n'
  731. ' x = x - 1\n'
  732. 'end do'
  733. )
  734. def test_FunctionPrototype_print():
  735. x = symbols('x')
  736. n = symbols('n', integer=True)
  737. vx = Variable(x, type=real)
  738. vn = Variable(n, type=integer)
  739. fp1 = FunctionPrototype(real, 'power', [vx, vn])
  740. # Should be changed to proper test once multi-line generation is working
  741. # see https://github.com/sympy/sympy/issues/15824
  742. raises(NotImplementedError, lambda: fcode(fp1))
  743. def test_FunctionDefinition_print():
  744. x = symbols('x')
  745. n = symbols('n', integer=True)
  746. vx = Variable(x, type=real)
  747. vn = Variable(n, type=integer)
  748. body = [Assignment(x, x**n), Return(x)]
  749. fd1 = FunctionDefinition(real, 'power', [vx, vn], body)
  750. # Should be changed to proper test once multi-line generation is working
  751. # see https://github.com/sympy/sympy/issues/15824
  752. raises(NotImplementedError, lambda: fcode(fd1))