1from sympy.core import (S, pi, oo, symbols, Function, Rational, Integer, 2 Tuple, Symbol, EulerGamma, GoldenRatio, Catalan, 3 Lambda, Mul, Pow, Mod, Eq, Ne, Le, Lt, Gt, Ge) 4from sympy.codegen.matrix_nodes import MatrixSolve 5from sympy.functions import (arg, atan2, bernoulli, beta, ceiling, chebyshevu, 6 chebyshevt, conjugate, DiracDelta, exp, expint, 7 factorial, floor, harmonic, Heaviside, im, 8 laguerre, LambertW, log, Max, Min, Piecewise, 9 polylog, re, RisingFactorial, sign, sinc, sqrt, 10 zeta, binomial, legendre) 11from sympy.functions import (sin, cos, tan, cot, sec, csc, asin, acos, acot, 12 atan, asec, acsc, sinh, cosh, tanh, coth, csch, 13 sech, asinh, acosh, atanh, acoth, asech, acsch) 14from sympy.testing.pytest import raises, XFAIL 15from sympy.utilities.lambdify import implemented_function 16from sympy.matrices import (eye, Matrix, MatrixSymbol, Identity, 17 HadamardProduct, SparseMatrix, HadamardPower) 18from sympy.functions.special.bessel import (jn, yn, besselj, bessely, besseli, 19 besselk, hankel1, hankel2, airyai, 20 airybi, airyaiprime, airybiprime) 21from sympy.functions.special.gamma_functions import (gamma, lowergamma, 22 uppergamma, loggamma, 23 polygamma) 24from sympy.functions.special.error_functions import (Chi, Ci, erf, erfc, erfi, 25 erfcinv, erfinv, fresnelc, 26 fresnels, li, Shi, Si, Li, 27 erf2) 28from sympy import octave_code 29from sympy import octave_code as mcode 30 31x, y, z = symbols('x,y,z') 32 33 34def test_Integer(): 35 assert mcode(Integer(67)) == "67" 36 assert mcode(Integer(-1)) == "-1" 37 38 39def test_Rational(): 40 assert mcode(Rational(3, 7)) == "3/7" 41 assert mcode(Rational(18, 9)) == "2" 42 assert mcode(Rational(3, -7)) == "-3/7" 43 assert mcode(Rational(-3, -7)) == "3/7" 44 assert mcode(x + Rational(3, 7)) == "x + 3/7" 45 assert mcode(Rational(3, 7)*x) == "3*x/7" 46 47 48def test_Relational(): 49 assert mcode(Eq(x, y)) == "x == y" 50 assert mcode(Ne(x, y)) == "x != y" 51 assert mcode(Le(x, y)) == "x <= y" 52 assert mcode(Lt(x, y)) == "x < y" 53 assert mcode(Gt(x, y)) == "x > y" 54 assert mcode(Ge(x, y)) == "x >= y" 55 56 57def test_Function(): 58 assert mcode(sin(x) ** cos(x)) == "sin(x).^cos(x)" 59 assert mcode(sign(x)) == "sign(x)" 60 assert mcode(exp(x)) == "exp(x)" 61 assert mcode(log(x)) == "log(x)" 62 assert mcode(factorial(x)) == "factorial(x)" 63 assert mcode(floor(x)) == "floor(x)" 64 assert mcode(atan2(y, x)) == "atan2(y, x)" 65 assert mcode(beta(x, y)) == 'beta(x, y)' 66 assert mcode(polylog(x, y)) == 'polylog(x, y)' 67 assert mcode(harmonic(x)) == 'harmonic(x)' 68 assert mcode(bernoulli(x)) == "bernoulli(x)" 69 assert mcode(bernoulli(x, y)) == "bernoulli(x, y)" 70 assert mcode(legendre(x, y)) == "legendre(x, y)" 71 72 73def test_Function_change_name(): 74 assert mcode(abs(x)) == "abs(x)" 75 assert mcode(ceiling(x)) == "ceil(x)" 76 assert mcode(arg(x)) == "angle(x)" 77 assert mcode(im(x)) == "imag(x)" 78 assert mcode(re(x)) == "real(x)" 79 assert mcode(conjugate(x)) == "conj(x)" 80 assert mcode(chebyshevt(y, x)) == "chebyshevT(y, x)" 81 assert mcode(chebyshevu(y, x)) == "chebyshevU(y, x)" 82 assert mcode(laguerre(x, y)) == "laguerreL(x, y)" 83 assert mcode(Chi(x)) == "coshint(x)" 84 assert mcode(Shi(x)) == "sinhint(x)" 85 assert mcode(Ci(x)) == "cosint(x)" 86 assert mcode(Si(x)) == "sinint(x)" 87 assert mcode(li(x)) == "logint(x)" 88 assert mcode(loggamma(x)) == "gammaln(x)" 89 assert mcode(polygamma(x, y)) == "psi(x, y)" 90 assert mcode(RisingFactorial(x, y)) == "pochhammer(x, y)" 91 assert mcode(DiracDelta(x)) == "dirac(x)" 92 assert mcode(DiracDelta(x, 3)) == "dirac(3, x)" 93 assert mcode(Heaviside(x)) == "heaviside(x, 1/2)" 94 assert mcode(Heaviside(x, y)) == "heaviside(x, y)" 95 assert mcode(binomial(x, y)) == "bincoeff(x, y)" 96 assert mcode(Mod(x, y)) == "mod(x, y)" 97 98 99def test_minmax(): 100 assert mcode(Max(x, y) + Min(x, y)) == "max(x, y) + min(x, y)" 101 assert mcode(Max(x, y, z)) == "max(x, max(y, z))" 102 assert mcode(Min(x, y, z)) == "min(x, min(y, z))" 103 104 105def test_Pow(): 106 assert mcode(x**3) == "x.^3" 107 assert mcode(x**(y**3)) == "x.^(y.^3)" 108 assert mcode(x**Rational(2, 3)) == 'x.^(2/3)' 109 g = implemented_function('g', Lambda(x, 2*x)) 110 assert mcode(1/(g(x)*3.5)**(x - y**x)/(x**2 + y)) == \ 111 "(3.5*2*x).^(-x + y.^x)./(x.^2 + y)" 112 # For issue 14160 113 assert mcode(Mul(-2, x, Pow(Mul(y,y,evaluate=False), -1, evaluate=False), 114 evaluate=False)) == '-2*x./(y.*y)' 115 116 117def test_basic_ops(): 118 assert mcode(x*y) == "x.*y" 119 assert mcode(x + y) == "x + y" 120 assert mcode(x - y) == "x - y" 121 assert mcode(-x) == "-x" 122 123 124def test_1_over_x_and_sqrt(): 125 # 1.0 and 0.5 would do something different in regular StrPrinter, 126 # but these are exact in IEEE floating point so no different here. 127 assert mcode(1/x) == '1./x' 128 assert mcode(x**-1) == mcode(x**-1.0) == '1./x' 129 assert mcode(1/sqrt(x)) == '1./sqrt(x)' 130 assert mcode(x**-S.Half) == mcode(x**-0.5) == '1./sqrt(x)' 131 assert mcode(sqrt(x)) == 'sqrt(x)' 132 assert mcode(x**S.Half) == mcode(x**0.5) == 'sqrt(x)' 133 assert mcode(1/pi) == '1/pi' 134 assert mcode(pi**-1) == mcode(pi**-1.0) == '1/pi' 135 assert mcode(pi**-0.5) == '1/sqrt(pi)' 136 137 138def test_mix_number_mult_symbols(): 139 assert mcode(3*x) == "3*x" 140 assert mcode(pi*x) == "pi*x" 141 assert mcode(3/x) == "3./x" 142 assert mcode(pi/x) == "pi./x" 143 assert mcode(x/3) == "x/3" 144 assert mcode(x/pi) == "x/pi" 145 assert mcode(x*y) == "x.*y" 146 assert mcode(3*x*y) == "3*x.*y" 147 assert mcode(3*pi*x*y) == "3*pi*x.*y" 148 assert mcode(x/y) == "x./y" 149 assert mcode(3*x/y) == "3*x./y" 150 assert mcode(x*y/z) == "x.*y./z" 151 assert mcode(x/y*z) == "x.*z./y" 152 assert mcode(1/x/y) == "1./(x.*y)" 153 assert mcode(2*pi*x/y/z) == "2*pi*x./(y.*z)" 154 assert mcode(3*pi/x) == "3*pi./x" 155 assert mcode(S(3)/5) == "3/5" 156 assert mcode(S(3)/5*x) == "3*x/5" 157 assert mcode(x/y/z) == "x./(y.*z)" 158 assert mcode((x+y)/z) == "(x + y)./z" 159 assert mcode((x+y)/(z+x)) == "(x + y)./(x + z)" 160 assert mcode((x+y)/EulerGamma) == "(x + y)/%s" % EulerGamma.evalf(17) 161 assert mcode(x/3/pi) == "x/(3*pi)" 162 assert mcode(S(3)/5*x*y/pi) == "3*x.*y/(5*pi)" 163 164 165def test_mix_number_pow_symbols(): 166 assert mcode(pi**3) == 'pi^3' 167 assert mcode(x**2) == 'x.^2' 168 assert mcode(x**(pi**3)) == 'x.^(pi^3)' 169 assert mcode(x**y) == 'x.^y' 170 assert mcode(x**(y**z)) == 'x.^(y.^z)' 171 assert mcode((x**y)**z) == '(x.^y).^z' 172 173 174def test_imag(): 175 I = S('I') 176 assert mcode(I) == "1i" 177 assert mcode(5*I) == "5i" 178 assert mcode((S(3)/2)*I) == "3*1i/2" 179 assert mcode(3+4*I) == "3 + 4i" 180 assert mcode(sqrt(3)*I) == "sqrt(3)*1i" 181 182 183def test_constants(): 184 assert mcode(pi) == "pi" 185 assert mcode(oo) == "inf" 186 assert mcode(-oo) == "-inf" 187 assert mcode(S.NegativeInfinity) == "-inf" 188 assert mcode(S.NaN) == "NaN" 189 assert mcode(S.Exp1) == "exp(1)" 190 assert mcode(exp(1)) == "exp(1)" 191 192 193def test_constants_other(): 194 assert mcode(2*GoldenRatio) == "2*(1+sqrt(5))/2" 195 assert mcode(2*Catalan) == "2*%s" % Catalan.evalf(17) 196 assert mcode(2*EulerGamma) == "2*%s" % EulerGamma.evalf(17) 197 198 199def test_boolean(): 200 assert mcode(x & y) == "x & y" 201 assert mcode(x | y) == "x | y" 202 assert mcode(~x) == "~x" 203 assert mcode(x & y & z) == "x & y & z" 204 assert mcode(x | y | z) == "x | y | z" 205 assert mcode((x & y) | z) == "z | x & y" 206 assert mcode((x | y) & z) == "z & (x | y)" 207 208 209def test_KroneckerDelta(): 210 from sympy.functions import KroneckerDelta 211 assert mcode(KroneckerDelta(x, y)) == "double(x == y)" 212 assert mcode(KroneckerDelta(x, y + 1)) == "double(x == (y + 1))" 213 assert mcode(KroneckerDelta(2**x, y)) == "double((2.^x) == y)" 214 215 216def test_Matrices(): 217 assert mcode(Matrix(1, 1, [10])) == "10" 218 A = Matrix([[1, sin(x/2), abs(x)], 219 [0, 1, pi], 220 [0, exp(1), ceiling(x)]]); 221 expected = "[1 sin(x/2) abs(x); 0 1 pi; 0 exp(1) ceil(x)]" 222 assert mcode(A) == expected 223 # row and columns 224 assert mcode(A[:,0]) == "[1; 0; 0]" 225 assert mcode(A[0,:]) == "[1 sin(x/2) abs(x)]" 226 # empty matrices 227 assert mcode(Matrix(0, 0, [])) == '[]' 228 assert mcode(Matrix(0, 3, [])) == 'zeros(0, 3)' 229 # annoying to read but correct 230 assert mcode(Matrix([[x, x - y, -y]])) == "[x x - y -y]" 231 232 233def test_vector_entries_hadamard(): 234 # For a row or column, user might to use the other dimension 235 A = Matrix([[1, sin(2/x), 3*pi/x/5]]) 236 assert mcode(A) == "[1 sin(2./x) 3*pi./(5*x)]" 237 assert mcode(A.T) == "[1; sin(2./x); 3*pi./(5*x)]" 238 239 240@XFAIL 241def test_Matrices_entries_not_hadamard(): 242 # For Matrix with col >= 2, row >= 2, they need to be scalars 243 # FIXME: is it worth worrying about this? Its not wrong, just 244 # leave it user's responsibility to put scalar data for x. 245 A = Matrix([[1, sin(2/x), 3*pi/x/5], [1, 2, x*y]]) 246 expected = ("[1 sin(2/x) 3*pi/(5*x);\n" 247 "1 2 x*y]") # <- we give x.*y 248 assert mcode(A) == expected 249 250 251def test_MatrixSymbol(): 252 n = Symbol('n', integer=True) 253 A = MatrixSymbol('A', n, n) 254 B = MatrixSymbol('B', n, n) 255 assert mcode(A*B) == "A*B" 256 assert mcode(B*A) == "B*A" 257 assert mcode(2*A*B) == "2*A*B" 258 assert mcode(B*2*A) == "2*B*A" 259 assert mcode(A*(B + 3*Identity(n))) == "A*(3*eye(n) + B)" 260 assert mcode(A**(x**2)) == "A^(x.^2)" 261 assert mcode(A**3) == "A^3" 262 assert mcode(A**S.Half) == "A^(1/2)" 263 264 265def test_MatrixSolve(): 266 n = Symbol('n', integer=True) 267 A = MatrixSymbol('A', n, n) 268 x = MatrixSymbol('x', n, 1) 269 assert mcode(MatrixSolve(A, x)) == "A \\ x" 270 271def test_special_matrices(): 272 assert mcode(6*Identity(3)) == "6*eye(3)" 273 274 275def test_containers(): 276 assert mcode([1, 2, 3, [4, 5, [6, 7]], 8, [9, 10], 11]) == \ 277 "{1, 2, 3, {4, 5, {6, 7}}, 8, {9, 10}, 11}" 278 assert mcode((1, 2, (3, 4))) == "{1, 2, {3, 4}}" 279 assert mcode([1]) == "{1}" 280 assert mcode((1,)) == "{1}" 281 assert mcode(Tuple(*[1, 2, 3])) == "{1, 2, 3}" 282 assert mcode((1, x*y, (3, x**2))) == "{1, x.*y, {3, x.^2}}" 283 # scalar, matrix, empty matrix and empty list 284 assert mcode((1, eye(3), Matrix(0, 0, []), [])) == "{1, [1 0 0; 0 1 0; 0 0 1], [], {}}" 285 286 287def test_octave_noninline(): 288 source = mcode((x+y)/Catalan, assign_to='me', inline=False) 289 expected = ( 290 "Catalan = %s;\n" 291 "me = (x + y)/Catalan;" 292 ) % Catalan.evalf(17) 293 assert source == expected 294 295 296def test_octave_piecewise(): 297 expr = Piecewise((x, x < 1), (x**2, True)) 298 assert mcode(expr) == "((x < 1).*(x) + (~(x < 1)).*(x.^2))" 299 assert mcode(expr, assign_to="r") == ( 300 "r = ((x < 1).*(x) + (~(x < 1)).*(x.^2));") 301 assert mcode(expr, assign_to="r", inline=False) == ( 302 "if (x < 1)\n" 303 " r = x;\n" 304 "else\n" 305 " r = x.^2;\n" 306 "end") 307 expr = Piecewise((x**2, x < 1), (x**3, x < 2), (x**4, x < 3), (x**5, True)) 308 expected = ("((x < 1).*(x.^2) + (~(x < 1)).*( ...\n" 309 "(x < 2).*(x.^3) + (~(x < 2)).*( ...\n" 310 "(x < 3).*(x.^4) + (~(x < 3)).*(x.^5))))") 311 assert mcode(expr) == expected 312 assert mcode(expr, assign_to="r") == "r = " + expected + ";" 313 assert mcode(expr, assign_to="r", inline=False) == ( 314 "if (x < 1)\n" 315 " r = x.^2;\n" 316 "elseif (x < 2)\n" 317 " r = x.^3;\n" 318 "elseif (x < 3)\n" 319 " r = x.^4;\n" 320 "else\n" 321 " r = x.^5;\n" 322 "end") 323 # Check that Piecewise without a True (default) condition error 324 expr = Piecewise((x, x < 1), (x**2, x > 1), (sin(x), x > 0)) 325 raises(ValueError, lambda: mcode(expr)) 326 327 328def test_octave_piecewise_times_const(): 329 pw = Piecewise((x, x < 1), (x**2, True)) 330 assert mcode(2*pw) == "2*((x < 1).*(x) + (~(x < 1)).*(x.^2))" 331 assert mcode(pw/x) == "((x < 1).*(x) + (~(x < 1)).*(x.^2))./x" 332 assert mcode(pw/(x*y)) == "((x < 1).*(x) + (~(x < 1)).*(x.^2))./(x.*y)" 333 assert mcode(pw/3) == "((x < 1).*(x) + (~(x < 1)).*(x.^2))/3" 334 335 336def test_octave_matrix_assign_to(): 337 A = Matrix([[1, 2, 3]]) 338 assert mcode(A, assign_to='a') == "a = [1 2 3];" 339 A = Matrix([[1, 2], [3, 4]]) 340 assert mcode(A, assign_to='A') == "A = [1 2; 3 4];" 341 342 343def test_octave_matrix_assign_to_more(): 344 # assigning to Symbol or MatrixSymbol requires lhs/rhs match 345 A = Matrix([[1, 2, 3]]) 346 B = MatrixSymbol('B', 1, 3) 347 C = MatrixSymbol('C', 2, 3) 348 assert mcode(A, assign_to=B) == "B = [1 2 3];" 349 raises(ValueError, lambda: mcode(A, assign_to=x)) 350 raises(ValueError, lambda: mcode(A, assign_to=C)) 351 352 353def test_octave_matrix_1x1(): 354 A = Matrix([[3]]) 355 B = MatrixSymbol('B', 1, 1) 356 C = MatrixSymbol('C', 1, 2) 357 assert mcode(A, assign_to=B) == "B = 3;" 358 # FIXME? 359 #assert mcode(A, assign_to=x) == "x = 3;" 360 raises(ValueError, lambda: mcode(A, assign_to=C)) 361 362 363def test_octave_matrix_elements(): 364 A = Matrix([[x, 2, x*y]]) 365 assert mcode(A[0, 0]**2 + A[0, 1] + A[0, 2]) == "x.^2 + x.*y + 2" 366 A = MatrixSymbol('AA', 1, 3) 367 assert mcode(A) == "AA" 368 assert mcode(A[0, 0]**2 + sin(A[0,1]) + A[0,2]) == \ 369 "sin(AA(1, 2)) + AA(1, 1).^2 + AA(1, 3)" 370 assert mcode(sum(A)) == "AA(1, 1) + AA(1, 2) + AA(1, 3)" 371 372 373def test_octave_boolean(): 374 assert mcode(True) == "true" 375 assert mcode(S.true) == "true" 376 assert mcode(False) == "false" 377 assert mcode(S.false) == "false" 378 379 380def test_octave_not_supported(): 381 assert mcode(S.ComplexInfinity) == ( 382 "% Not supported in Octave:\n" 383 "% ComplexInfinity\n" 384 "zoo" 385 ) 386 f = Function('f') 387 assert mcode(f(x).diff(x)) == ( 388 "% Not supported in Octave:\n" 389 "% Derivative\n" 390 "Derivative(f(x), x)" 391 ) 392 393 394def test_octave_not_supported_not_on_whitelist(): 395 from sympy import assoc_laguerre 396 assert mcode(assoc_laguerre(x, y, z)) == ( 397 "% Not supported in Octave:\n" 398 "% assoc_laguerre\n" 399 "assoc_laguerre(x, y, z)" 400 ) 401 402 403def test_octave_expint(): 404 assert mcode(expint(1, x)) == "expint(x)" 405 assert mcode(expint(2, x)) == ( 406 "% Not supported in Octave:\n" 407 "% expint\n" 408 "expint(2, x)" 409 ) 410 assert mcode(expint(y, x)) == ( 411 "% Not supported in Octave:\n" 412 "% expint\n" 413 "expint(y, x)" 414 ) 415 416 417def test_trick_indent_with_end_else_words(): 418 # words starting with "end" or "else" do not confuse the indenter 419 t1 = S('endless'); 420 t2 = S('elsewhere'); 421 pw = Piecewise((t1, x < 0), (t2, x <= 1), (1, True)) 422 assert mcode(pw, inline=False) == ( 423 "if (x < 0)\n" 424 " endless\n" 425 "elseif (x <= 1)\n" 426 " elsewhere\n" 427 "else\n" 428 " 1\n" 429 "end") 430 431 432def test_hadamard(): 433 A = MatrixSymbol('A', 3, 3) 434 B = MatrixSymbol('B', 3, 3) 435 v = MatrixSymbol('v', 3, 1) 436 h = MatrixSymbol('h', 1, 3) 437 C = HadamardProduct(A, B) 438 n = Symbol('n') 439 assert mcode(C) == "A.*B" 440 assert mcode(C*v) == "(A.*B)*v" 441 assert mcode(h*C*v) == "h*(A.*B)*v" 442 assert mcode(C*A) == "(A.*B)*A" 443 # mixing Hadamard and scalar strange b/c we vectorize scalars 444 assert mcode(C*x*y) == "(x.*y)*(A.*B)" 445 446 # Testing HadamardPower: 447 assert mcode(HadamardPower(A, n)) == "A.**n" 448 assert mcode(HadamardPower(A, 1+n)) == "A.**(n + 1)" 449 assert mcode(HadamardPower(A*B.T, 1+n)) == "(A*B.T).**(n + 1)" 450 451 452def test_sparse(): 453 M = SparseMatrix(5, 6, {}) 454 M[2, 2] = 10; 455 M[1, 2] = 20; 456 M[1, 3] = 22; 457 M[0, 3] = 30; 458 M[3, 0] = x*y; 459 assert mcode(M) == ( 460 "sparse([4 2 3 1 2], [1 3 3 4 4], [x.*y 20 10 30 22], 5, 6)" 461 ) 462 463 464def test_sinc(): 465 assert mcode(sinc(x)) == 'sinc(x/pi)' 466 assert mcode(sinc(x + 3)) == 'sinc((x + 3)/pi)' 467 assert mcode(sinc(pi*(x + 3))) == 'sinc(x + 3)' 468 469 470def test_trigfun(): 471 for f in (sin, cos, tan, cot, sec, csc, asin, acos, acot, atan, asec, acsc, 472 sinh, cosh, tanh, coth, csch, sech, asinh, acosh, atanh, acoth, 473 asech, acsch): 474 assert octave_code(f(x) == f.__name__ + '(x)') 475 476 477def test_specfun(): 478 n = Symbol('n') 479 for f in [besselj, bessely, besseli, besselk]: 480 assert octave_code(f(n, x)) == f.__name__ + '(n, x)' 481 for f in (erfc, erfi, erf, erfinv, erfcinv, fresnelc, fresnels, gamma): 482 assert octave_code(f(x)) == f.__name__ + '(x)' 483 assert octave_code(hankel1(n, x)) == 'besselh(n, 1, x)' 484 assert octave_code(hankel2(n, x)) == 'besselh(n, 2, x)' 485 assert octave_code(airyai(x)) == 'airy(0, x)' 486 assert octave_code(airyaiprime(x)) == 'airy(1, x)' 487 assert octave_code(airybi(x)) == 'airy(2, x)' 488 assert octave_code(airybiprime(x)) == 'airy(3, x)' 489 assert octave_code(uppergamma(n, x)) == '(gammainc(x, n, \'upper\').*gamma(n))' 490 assert octave_code(lowergamma(n, x)) == '(gammainc(x, n).*gamma(n))' 491 assert octave_code(z**lowergamma(n, x)) == 'z.^(gammainc(x, n).*gamma(n))' 492 assert octave_code(jn(n, x)) == 'sqrt(2)*sqrt(pi)*sqrt(1./x).*besselj(n + 1/2, x)/2' 493 assert octave_code(yn(n, x)) == 'sqrt(2)*sqrt(pi)*sqrt(1./x).*bessely(n + 1/2, x)/2' 494 assert octave_code(LambertW(x)) == 'lambertw(x)' 495 assert octave_code(LambertW(x, n)) == 'lambertw(n, x)' 496 497 498def test_MatrixElement_printing(): 499 # test cases for issue #11821 500 A = MatrixSymbol("A", 1, 3) 501 B = MatrixSymbol("B", 1, 3) 502 C = MatrixSymbol("C", 1, 3) 503 504 assert mcode(A[0, 0]) == "A(1, 1)" 505 assert mcode(3 * A[0, 0]) == "3*A(1, 1)" 506 507 F = C[0, 0].subs(C, A - B) 508 assert mcode(F) == "(A - B)(1, 1)" 509 510 511def test_zeta_printing_issue_14820(): 512 assert octave_code(zeta(x)) == 'zeta(x)' 513 assert octave_code(zeta(x, y)) == '% Not supported in Octave:\n% zeta\nzeta(x, y)' 514 515 516def test_automatic_rewrite(): 517 assert octave_code(Li(x)) == 'logint(x) - logint(2)' 518 assert octave_code(erf2(x, y)) == '-erf(x) + erf(y)' 519