test_tensorflow.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. import random
  2. from sympy.core.function import Derivative
  3. from sympy.core.symbol import symbols
  4. from sympy import Piecewise
  5. from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct, ArrayAdd, \
  6. PermuteDims, ArrayDiagonal
  7. from sympy.core.relational import Eq, Ne, Ge, Gt, Le, Lt
  8. from sympy.external import import_module
  9. from sympy.functions import \
  10. Abs, ceiling, exp, floor, sign, sin, asin, sqrt, cos, \
  11. acos, tan, atan, atan2, cosh, acosh, sinh, asinh, tanh, atanh, \
  12. re, im, arg, erf, loggamma, log
  13. from sympy.codegen.cfunctions import isnan, isinf
  14. from sympy.matrices import Matrix, MatrixBase, eye, randMatrix
  15. from sympy.matrices.expressions import \
  16. Determinant, HadamardProduct, Inverse, MatrixSymbol, Trace
  17. from sympy.printing.tensorflow import tensorflow_code
  18. from sympy.tensor.array.expressions.from_matrix_to_array import convert_matrix_to_array
  19. from sympy.utilities.lambdify import lambdify
  20. from sympy.testing.pytest import skip
  21. from sympy.testing.pytest import XFAIL
  22. tf = tensorflow = import_module("tensorflow")
  23. if tensorflow:
  24. # Hide Tensorflow warnings
  25. import os
  26. os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
  27. M = MatrixSymbol("M", 3, 3)
  28. N = MatrixSymbol("N", 3, 3)
  29. P = MatrixSymbol("P", 3, 3)
  30. Q = MatrixSymbol("Q", 3, 3)
  31. x, y, z, t = symbols("x y z t")
  32. if tf is not None:
  33. llo = [list(range(i, i+3)) for i in range(0, 9, 3)]
  34. m3x3 = tf.constant(llo)
  35. m3x3sympy = Matrix(llo)
  36. def _compare_tensorflow_matrix(variables, expr, use_float=False):
  37. f = lambdify(variables, expr, 'tensorflow')
  38. if not use_float:
  39. random_matrices = [randMatrix(v.rows, v.cols) for v in variables]
  40. else:
  41. random_matrices = [randMatrix(v.rows, v.cols)/100. for v in variables]
  42. graph = tf.Graph()
  43. r = None
  44. with graph.as_default():
  45. random_variables = [eval(tensorflow_code(i)) for i in random_matrices]
  46. session = tf.compat.v1.Session(graph=graph)
  47. r = session.run(f(*random_variables))
  48. e = expr.subs(dict(zip(variables, random_matrices)))
  49. e = e.doit()
  50. if e.is_Matrix:
  51. if not isinstance(e, MatrixBase):
  52. e = e.as_explicit()
  53. e = e.tolist()
  54. if not use_float:
  55. assert (r == e).all()
  56. else:
  57. r = [i for row in r for i in row]
  58. e = [i for row in e for i in row]
  59. assert all(
  60. abs(a-b) < 10**-(4-int(log(abs(a), 10))) for a, b in zip(r, e))
  61. # Creating a custom inverse test.
  62. # See https://github.com/sympy/sympy/issues/18469
  63. def _compare_tensorflow_matrix_inverse(variables, expr, use_float=False):
  64. f = lambdify(variables, expr, 'tensorflow')
  65. if not use_float:
  66. random_matrices = [eye(v.rows, v.cols)*4 for v in variables]
  67. else:
  68. random_matrices = [eye(v.rows, v.cols)*3.14 for v in variables]
  69. graph = tf.Graph()
  70. r = None
  71. with graph.as_default():
  72. random_variables = [eval(tensorflow_code(i)) for i in random_matrices]
  73. session = tf.compat.v1.Session(graph=graph)
  74. r = session.run(f(*random_variables))
  75. e = expr.subs(dict(zip(variables, random_matrices)))
  76. e = e.doit()
  77. if e.is_Matrix:
  78. if not isinstance(e, MatrixBase):
  79. e = e.as_explicit()
  80. e = e.tolist()
  81. if not use_float:
  82. assert (r == e).all()
  83. else:
  84. r = [i for row in r for i in row]
  85. e = [i for row in e for i in row]
  86. assert all(
  87. abs(a-b) < 10**-(4-int(log(abs(a), 10))) for a, b in zip(r, e))
  88. def _compare_tensorflow_matrix_scalar(variables, expr):
  89. f = lambdify(variables, expr, 'tensorflow')
  90. random_matrices = [
  91. randMatrix(v.rows, v.cols).evalf() / 100 for v in variables]
  92. graph = tf.Graph()
  93. r = None
  94. with graph.as_default():
  95. random_variables = [eval(tensorflow_code(i)) for i in random_matrices]
  96. session = tf.compat.v1.Session(graph=graph)
  97. r = session.run(f(*random_variables))
  98. e = expr.subs(dict(zip(variables, random_matrices)))
  99. e = e.doit()
  100. assert abs(r-e) < 10**-6
  101. def _compare_tensorflow_scalar(
  102. variables, expr, rng=lambda: random.randint(0, 10)):
  103. f = lambdify(variables, expr, 'tensorflow')
  104. rvs = [rng() for v in variables]
  105. graph = tf.Graph()
  106. r = None
  107. with graph.as_default():
  108. tf_rvs = [eval(tensorflow_code(i)) for i in rvs]
  109. session = tf.compat.v1.Session(graph=graph)
  110. r = session.run(f(*tf_rvs))
  111. e = expr.subs(dict(zip(variables, rvs))).evalf().doit()
  112. assert abs(r-e) < 10**-6
  113. def _compare_tensorflow_relational(
  114. variables, expr, rng=lambda: random.randint(0, 10)):
  115. f = lambdify(variables, expr, 'tensorflow')
  116. rvs = [rng() for v in variables]
  117. graph = tf.Graph()
  118. r = None
  119. with graph.as_default():
  120. tf_rvs = [eval(tensorflow_code(i)) for i in rvs]
  121. session = tf.compat.v1.Session(graph=graph)
  122. r = session.run(f(*tf_rvs))
  123. e = expr.subs(dict(zip(variables, rvs))).doit()
  124. assert r == e
  125. def test_tensorflow_printing():
  126. assert tensorflow_code(eye(3)) == \
  127. "tensorflow.constant([[1, 0, 0], [0, 1, 0], [0, 0, 1]])"
  128. expr = Matrix([[x, sin(y)], [exp(z), -t]])
  129. assert tensorflow_code(expr) == \
  130. "tensorflow.Variable(" \
  131. "[[x, tensorflow.math.sin(y)]," \
  132. " [tensorflow.math.exp(z), -t]])"
  133. # This (random) test is XFAIL because it fails occasionally
  134. # See https://github.com/sympy/sympy/issues/18469
  135. @XFAIL
  136. def test_tensorflow_math():
  137. if not tf:
  138. skip("TensorFlow not installed")
  139. expr = Abs(x)
  140. assert tensorflow_code(expr) == "tensorflow.math.abs(x)"
  141. _compare_tensorflow_scalar((x,), expr)
  142. expr = sign(x)
  143. assert tensorflow_code(expr) == "tensorflow.math.sign(x)"
  144. _compare_tensorflow_scalar((x,), expr)
  145. expr = ceiling(x)
  146. assert tensorflow_code(expr) == "tensorflow.math.ceil(x)"
  147. _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random())
  148. expr = floor(x)
  149. assert tensorflow_code(expr) == "tensorflow.math.floor(x)"
  150. _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random())
  151. expr = exp(x)
  152. assert tensorflow_code(expr) == "tensorflow.math.exp(x)"
  153. _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random())
  154. expr = sqrt(x)
  155. assert tensorflow_code(expr) == "tensorflow.math.sqrt(x)"
  156. _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random())
  157. expr = x ** 4
  158. assert tensorflow_code(expr) == "tensorflow.math.pow(x, 4)"
  159. _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random())
  160. expr = cos(x)
  161. assert tensorflow_code(expr) == "tensorflow.math.cos(x)"
  162. _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random())
  163. expr = acos(x)
  164. assert tensorflow_code(expr) == "tensorflow.math.acos(x)"
  165. _compare_tensorflow_scalar((x,), expr, rng=lambda: random.uniform(0, 0.95))
  166. expr = sin(x)
  167. assert tensorflow_code(expr) == "tensorflow.math.sin(x)"
  168. _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random())
  169. expr = asin(x)
  170. assert tensorflow_code(expr) == "tensorflow.math.asin(x)"
  171. _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random())
  172. expr = tan(x)
  173. assert tensorflow_code(expr) == "tensorflow.math.tan(x)"
  174. _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random())
  175. expr = atan(x)
  176. assert tensorflow_code(expr) == "tensorflow.math.atan(x)"
  177. _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random())
  178. expr = atan2(y, x)
  179. assert tensorflow_code(expr) == "tensorflow.math.atan2(y, x)"
  180. _compare_tensorflow_scalar((y, x), expr, rng=lambda: random.random())
  181. expr = cosh(x)
  182. assert tensorflow_code(expr) == "tensorflow.math.cosh(x)"
  183. _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random())
  184. expr = acosh(x)
  185. assert tensorflow_code(expr) == "tensorflow.math.acosh(x)"
  186. _compare_tensorflow_scalar((x,), expr, rng=lambda: random.uniform(1, 2))
  187. expr = sinh(x)
  188. assert tensorflow_code(expr) == "tensorflow.math.sinh(x)"
  189. _compare_tensorflow_scalar((x,), expr, rng=lambda: random.uniform(1, 2))
  190. expr = asinh(x)
  191. assert tensorflow_code(expr) == "tensorflow.math.asinh(x)"
  192. _compare_tensorflow_scalar((x,), expr, rng=lambda: random.uniform(1, 2))
  193. expr = tanh(x)
  194. assert tensorflow_code(expr) == "tensorflow.math.tanh(x)"
  195. _compare_tensorflow_scalar((x,), expr, rng=lambda: random.uniform(1, 2))
  196. expr = atanh(x)
  197. assert tensorflow_code(expr) == "tensorflow.math.atanh(x)"
  198. _compare_tensorflow_scalar(
  199. (x,), expr, rng=lambda: random.uniform(-.5, .5))
  200. expr = erf(x)
  201. assert tensorflow_code(expr) == "tensorflow.math.erf(x)"
  202. _compare_tensorflow_scalar(
  203. (x,), expr, rng=lambda: random.random())
  204. expr = loggamma(x)
  205. assert tensorflow_code(expr) == "tensorflow.math.lgamma(x)"
  206. _compare_tensorflow_scalar(
  207. (x,), expr, rng=lambda: random.random())
  208. def test_tensorflow_complexes():
  209. assert tensorflow_code(re(x)) == "tensorflow.math.real(x)"
  210. assert tensorflow_code(im(x)) == "tensorflow.math.imag(x)"
  211. assert tensorflow_code(arg(x)) == "tensorflow.math.angle(x)"
  212. def test_tensorflow_relational():
  213. if not tf:
  214. skip("TensorFlow not installed")
  215. expr = Eq(x, y)
  216. assert tensorflow_code(expr) == "tensorflow.math.equal(x, y)"
  217. _compare_tensorflow_relational((x, y), expr)
  218. expr = Ne(x, y)
  219. assert tensorflow_code(expr) == "tensorflow.math.not_equal(x, y)"
  220. _compare_tensorflow_relational((x, y), expr)
  221. expr = Ge(x, y)
  222. assert tensorflow_code(expr) == "tensorflow.math.greater_equal(x, y)"
  223. _compare_tensorflow_relational((x, y), expr)
  224. expr = Gt(x, y)
  225. assert tensorflow_code(expr) == "tensorflow.math.greater(x, y)"
  226. _compare_tensorflow_relational((x, y), expr)
  227. expr = Le(x, y)
  228. assert tensorflow_code(expr) == "tensorflow.math.less_equal(x, y)"
  229. _compare_tensorflow_relational((x, y), expr)
  230. expr = Lt(x, y)
  231. assert tensorflow_code(expr) == "tensorflow.math.less(x, y)"
  232. _compare_tensorflow_relational((x, y), expr)
  233. # This (random) test is XFAIL because it fails occasionally
  234. # See https://github.com/sympy/sympy/issues/18469
  235. @XFAIL
  236. def test_tensorflow_matrices():
  237. if not tf:
  238. skip("TensorFlow not installed")
  239. expr = M
  240. assert tensorflow_code(expr) == "M"
  241. _compare_tensorflow_matrix((M,), expr)
  242. expr = M + N
  243. assert tensorflow_code(expr) == "tensorflow.math.add(M, N)"
  244. _compare_tensorflow_matrix((M, N), expr)
  245. expr = M * N
  246. assert tensorflow_code(expr) == "tensorflow.linalg.matmul(M, N)"
  247. _compare_tensorflow_matrix((M, N), expr)
  248. expr = HadamardProduct(M, N)
  249. assert tensorflow_code(expr) == "tensorflow.math.multiply(M, N)"
  250. _compare_tensorflow_matrix((M, N), expr)
  251. expr = M*N*P*Q
  252. assert tensorflow_code(expr) == \
  253. "tensorflow.linalg.matmul(" \
  254. "tensorflow.linalg.matmul(" \
  255. "tensorflow.linalg.matmul(M, N), P), Q)"
  256. _compare_tensorflow_matrix((M, N, P, Q), expr)
  257. expr = M**3
  258. assert tensorflow_code(expr) == \
  259. "tensorflow.linalg.matmul(tensorflow.linalg.matmul(M, M), M)"
  260. _compare_tensorflow_matrix((M,), expr)
  261. expr = Trace(M)
  262. assert tensorflow_code(expr) == "tensorflow.linalg.trace(M)"
  263. _compare_tensorflow_matrix((M,), expr)
  264. expr = Determinant(M)
  265. assert tensorflow_code(expr) == "tensorflow.linalg.det(M)"
  266. _compare_tensorflow_matrix_scalar((M,), expr)
  267. expr = Inverse(M)
  268. assert tensorflow_code(expr) == "tensorflow.linalg.inv(M)"
  269. _compare_tensorflow_matrix_inverse((M,), expr, use_float=True)
  270. expr = M.T
  271. assert tensorflow_code(expr, tensorflow_version='1.14') == \
  272. "tensorflow.linalg.matrix_transpose(M)"
  273. assert tensorflow_code(expr, tensorflow_version='1.13') == \
  274. "tensorflow.matrix_transpose(M)"
  275. _compare_tensorflow_matrix((M,), expr)
  276. def test_codegen_einsum():
  277. if not tf:
  278. skip("TensorFlow not installed")
  279. graph = tf.Graph()
  280. with graph.as_default():
  281. session = tf.compat.v1.Session(graph=graph)
  282. M = MatrixSymbol("M", 2, 2)
  283. N = MatrixSymbol("N", 2, 2)
  284. cg = convert_matrix_to_array(M * N)
  285. f = lambdify((M, N), cg, 'tensorflow')
  286. ma = tf.constant([[1, 2], [3, 4]])
  287. mb = tf.constant([[1,-2], [-1, 3]])
  288. y = session.run(f(ma, mb))
  289. c = session.run(tf.matmul(ma, mb))
  290. assert (y == c).all()
  291. def test_codegen_extra():
  292. if not tf:
  293. skip("TensorFlow not installed")
  294. graph = tf.Graph()
  295. with graph.as_default():
  296. session = tf.compat.v1.Session()
  297. M = MatrixSymbol("M", 2, 2)
  298. N = MatrixSymbol("N", 2, 2)
  299. P = MatrixSymbol("P", 2, 2)
  300. Q = MatrixSymbol("Q", 2, 2)
  301. ma = tf.constant([[1, 2], [3, 4]])
  302. mb = tf.constant([[1,-2], [-1, 3]])
  303. mc = tf.constant([[2, 0], [1, 2]])
  304. md = tf.constant([[1,-1], [4, 7]])
  305. cg = ArrayTensorProduct(M, N)
  306. assert tensorflow_code(cg) == \
  307. 'tensorflow.linalg.einsum("ab,cd", M, N)'
  308. f = lambdify((M, N), cg, 'tensorflow')
  309. y = session.run(f(ma, mb))
  310. c = session.run(tf.einsum("ij,kl", ma, mb))
  311. assert (y == c).all()
  312. cg = ArrayAdd(M, N)
  313. assert tensorflow_code(cg) == 'tensorflow.math.add(M, N)'
  314. f = lambdify((M, N), cg, 'tensorflow')
  315. y = session.run(f(ma, mb))
  316. c = session.run(ma + mb)
  317. assert (y == c).all()
  318. cg = ArrayAdd(M, N, P)
  319. assert tensorflow_code(cg) == \
  320. 'tensorflow.math.add(tensorflow.math.add(M, N), P)'
  321. f = lambdify((M, N, P), cg, 'tensorflow')
  322. y = session.run(f(ma, mb, mc))
  323. c = session.run(ma + mb + mc)
  324. assert (y == c).all()
  325. cg = ArrayAdd(M, N, P, Q)
  326. assert tensorflow_code(cg) == \
  327. 'tensorflow.math.add(' \
  328. 'tensorflow.math.add(tensorflow.math.add(M, N), P), Q)'
  329. f = lambdify((M, N, P, Q), cg, 'tensorflow')
  330. y = session.run(f(ma, mb, mc, md))
  331. c = session.run(ma + mb + mc + md)
  332. assert (y == c).all()
  333. cg = PermuteDims(M, [1, 0])
  334. assert tensorflow_code(cg) == 'tensorflow.transpose(M, [1, 0])'
  335. f = lambdify((M,), cg, 'tensorflow')
  336. y = session.run(f(ma))
  337. c = session.run(tf.transpose(ma))
  338. assert (y == c).all()
  339. cg = PermuteDims(ArrayTensorProduct(M, N), [1, 2, 3, 0])
  340. assert tensorflow_code(cg) == \
  341. 'tensorflow.transpose(' \
  342. 'tensorflow.linalg.einsum("ab,cd", M, N), [1, 2, 3, 0])'
  343. f = lambdify((M, N), cg, 'tensorflow')
  344. y = session.run(f(ma, mb))
  345. c = session.run(tf.transpose(tf.einsum("ab,cd", ma, mb), [1, 2, 3, 0]))
  346. assert (y == c).all()
  347. cg = ArrayDiagonal(ArrayTensorProduct(M, N), (1, 2))
  348. assert tensorflow_code(cg) == \
  349. 'tensorflow.linalg.einsum("ab,bc->acb", M, N)'
  350. f = lambdify((M, N), cg, 'tensorflow')
  351. y = session.run(f(ma, mb))
  352. c = session.run(tf.einsum("ab,bc->acb", ma, mb))
  353. assert (y == c).all()
  354. def test_MatrixElement_printing():
  355. A = MatrixSymbol("A", 1, 3)
  356. B = MatrixSymbol("B", 1, 3)
  357. C = MatrixSymbol("C", 1, 3)
  358. assert tensorflow_code(A[0, 0]) == "A[0, 0]"
  359. assert tensorflow_code(3 * A[0, 0]) == "3*A[0, 0]"
  360. F = C[0, 0].subs(C, A - B)
  361. assert tensorflow_code(F) == "(tensorflow.math.add((-1)*B, A))[0, 0]"
  362. def test_tensorflow_Derivative():
  363. expr = Derivative(sin(x), x)
  364. assert tensorflow_code(expr) == \
  365. "tensorflow.gradients(tensorflow.math.sin(x), x)[0]"
  366. def test_tensorflow_isnan_isinf():
  367. if not tf:
  368. skip("TensorFlow not installed")
  369. # Test for isnan
  370. x = symbols("x")
  371. # Return 0 if x is of nan value, and 1 otherwise
  372. expression = Piecewise((0.0, isnan(x)), (1.0, True))
  373. printed_code = tensorflow_code(expression)
  374. expected_printed_code = "tensorflow.where(tensorflow.math.is_nan(x), 0.0, 1.0)"
  375. assert tensorflow_code(expression) == expected_printed_code, f"Incorrect printed result {printed_code}, expected {expected_printed_code}"
  376. for _input, _expected in [(float('nan'), 0.0), (float('inf'), 1.0), (float('-inf'), 1.0), (1.0, 1.0)]:
  377. _output = lambdify((x), expression, modules="tensorflow")(x=tf.constant([_input]))
  378. assert (_output == _expected).numpy().all()
  379. # Test for isinf
  380. x = symbols("x")
  381. # Return 0 if x is of nan value, and 1 otherwise
  382. expression = Piecewise((0.0, isinf(x)), (1.0, True))
  383. printed_code = tensorflow_code(expression)
  384. expected_printed_code = "tensorflow.where(tensorflow.math.is_inf(x), 0.0, 1.0)"
  385. assert tensorflow_code(expression) == expected_printed_code, f"Incorrect printed result {printed_code}, expected {expected_printed_code}"
  386. for _input, _expected in [(float('inf'), 0.0), (float('-inf'), 0.0), (float('nan'), 1.0), (1.0, 1.0)]:
  387. _output = lambdify((x), expression, modules="tensorflow")(x=tf.constant([_input]))
  388. assert (_output == _expected).numpy().all()