You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
197 lines
7.3 KiB
197 lines
7.3 KiB
import sympy
|
|
from sympy.parsing.sympy_parser import (
|
|
parse_expr,
|
|
standard_transformations,
|
|
convert_xor,
|
|
implicit_multiplication_application,
|
|
implicit_multiplication,
|
|
implicit_application,
|
|
function_exponentiation,
|
|
split_symbols,
|
|
split_symbols_custom,
|
|
_token_splittable
|
|
)
|
|
from sympy.testing.pytest import raises
|
|
|
|
|
|
def test_implicit_multiplication():
|
|
cases = {
|
|
'5x': '5*x',
|
|
'abc': 'a*b*c',
|
|
'3sin(x)': '3*sin(x)',
|
|
'(x+1)(x+2)': '(x+1)*(x+2)',
|
|
'(5 x**2)sin(x)': '(5*x**2)*sin(x)',
|
|
'2 sin(x) cos(x)': '2*sin(x)*cos(x)',
|
|
'pi x': 'pi*x',
|
|
'x pi': 'x*pi',
|
|
'E x': 'E*x',
|
|
'EulerGamma y': 'EulerGamma*y',
|
|
'E pi': 'E*pi',
|
|
'pi (x + 2)': 'pi*(x+2)',
|
|
'(x + 2) pi': '(x+2)*pi',
|
|
'pi sin(x)': 'pi*sin(x)',
|
|
}
|
|
transformations = standard_transformations + (convert_xor,)
|
|
transformations2 = transformations + (split_symbols,
|
|
implicit_multiplication)
|
|
for case in cases:
|
|
implicit = parse_expr(case, transformations=transformations2)
|
|
normal = parse_expr(cases[case], transformations=transformations)
|
|
assert(implicit == normal)
|
|
|
|
application = ['sin x', 'cos 2*x', 'sin cos x']
|
|
for case in application:
|
|
raises(SyntaxError,
|
|
lambda: parse_expr(case, transformations=transformations2))
|
|
raises(TypeError,
|
|
lambda: parse_expr('sin**2(x)', transformations=transformations2))
|
|
|
|
|
|
def test_implicit_application():
|
|
cases = {
|
|
'factorial': 'factorial',
|
|
'sin x': 'sin(x)',
|
|
'tan y**3': 'tan(y**3)',
|
|
'cos 2*x': 'cos(2*x)',
|
|
'(cot)': 'cot',
|
|
'sin cos tan x': 'sin(cos(tan(x)))'
|
|
}
|
|
transformations = standard_transformations + (convert_xor,)
|
|
transformations2 = transformations + (implicit_application,)
|
|
for case in cases:
|
|
implicit = parse_expr(case, transformations=transformations2)
|
|
normal = parse_expr(cases[case], transformations=transformations)
|
|
assert(implicit == normal), (implicit, normal)
|
|
|
|
multiplication = ['x y', 'x sin x', '2x']
|
|
for case in multiplication:
|
|
raises(SyntaxError,
|
|
lambda: parse_expr(case, transformations=transformations2))
|
|
raises(TypeError,
|
|
lambda: parse_expr('sin**2(x)', transformations=transformations2))
|
|
|
|
|
|
|
|
def test_function_exponentiation():
|
|
cases = {
|
|
'sin**2(x)': 'sin(x)**2',
|
|
'exp^y(z)': 'exp(z)^y',
|
|
'sin**2(E^(x))': 'sin(E^(x))**2'
|
|
}
|
|
transformations = standard_transformations + (convert_xor,)
|
|
transformations2 = transformations + (function_exponentiation,)
|
|
for case in cases:
|
|
implicit = parse_expr(case, transformations=transformations2)
|
|
normal = parse_expr(cases[case], transformations=transformations)
|
|
assert(implicit == normal)
|
|
|
|
other_implicit = ['x y', 'x sin x', '2x', 'sin x',
|
|
'cos 2*x', 'sin cos x']
|
|
for case in other_implicit:
|
|
raises(SyntaxError,
|
|
lambda: parse_expr(case, transformations=transformations2))
|
|
|
|
assert parse_expr('x**2', local_dict={ 'x': sympy.Symbol('x') },
|
|
transformations=transformations2) == parse_expr('x**2')
|
|
|
|
|
|
def test_symbol_splitting():
|
|
# By default Greek letter names should not be split (lambda is a keyword
|
|
# so skip it)
|
|
transformations = standard_transformations + (split_symbols,)
|
|
greek_letters = ('alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta',
|
|
'eta', 'theta', 'iota', 'kappa', 'mu', 'nu', 'xi',
|
|
'omicron', 'pi', 'rho', 'sigma', 'tau', 'upsilon',
|
|
'phi', 'chi', 'psi', 'omega')
|
|
|
|
for letter in greek_letters:
|
|
assert(parse_expr(letter, transformations=transformations) ==
|
|
parse_expr(letter))
|
|
|
|
# Make sure symbol splitting resolves names
|
|
transformations += (implicit_multiplication,)
|
|
local_dict = { 'e': sympy.E }
|
|
cases = {
|
|
'xe': 'E*x',
|
|
'Iy': 'I*y',
|
|
'ee': 'E*E',
|
|
}
|
|
for case, expected in cases.items():
|
|
assert(parse_expr(case, local_dict=local_dict,
|
|
transformations=transformations) ==
|
|
parse_expr(expected))
|
|
|
|
# Make sure custom splitting works
|
|
def can_split(symbol):
|
|
if symbol not in ('unsplittable', 'names'):
|
|
return _token_splittable(symbol)
|
|
return False
|
|
transformations = standard_transformations
|
|
transformations += (split_symbols_custom(can_split),
|
|
implicit_multiplication)
|
|
|
|
assert(parse_expr('unsplittable', transformations=transformations) ==
|
|
parse_expr('unsplittable'))
|
|
assert(parse_expr('names', transformations=transformations) ==
|
|
parse_expr('names'))
|
|
assert(parse_expr('xy', transformations=transformations) ==
|
|
parse_expr('x*y'))
|
|
for letter in greek_letters:
|
|
assert(parse_expr(letter, transformations=transformations) ==
|
|
parse_expr(letter))
|
|
|
|
|
|
def test_all_implicit_steps():
|
|
cases = {
|
|
'2x': '2*x', # implicit multiplication
|
|
'x y': 'x*y',
|
|
'xy': 'x*y',
|
|
'sin x': 'sin(x)', # add parentheses
|
|
'2sin x': '2*sin(x)',
|
|
'x y z': 'x*y*z',
|
|
'sin(2 * 3x)': 'sin(2 * 3 * x)',
|
|
'sin(x) (1 + cos(x))': 'sin(x) * (1 + cos(x))',
|
|
'(x + 2) sin(x)': '(x + 2) * sin(x)',
|
|
'(x + 2) sin x': '(x + 2) * sin(x)',
|
|
'sin(sin x)': 'sin(sin(x))',
|
|
'sin x!': 'sin(factorial(x))',
|
|
'sin x!!': 'sin(factorial2(x))',
|
|
'factorial': 'factorial', # don't apply a bare function
|
|
'x sin x': 'x * sin(x)', # both application and multiplication
|
|
'xy sin x': 'x * y * sin(x)',
|
|
'(x+2)(x+3)': '(x + 2) * (x+3)',
|
|
'x**2 + 2xy + y**2': 'x**2 + 2 * x * y + y**2', # split the xy
|
|
'pi': 'pi', # don't mess with constants
|
|
'None': 'None',
|
|
'ln sin x': 'ln(sin(x))', # multiple implicit function applications
|
|
'factorial': 'factorial', # don't add parentheses
|
|
'sin x**2': 'sin(x**2)', # implicit application to an exponential
|
|
'alpha': 'Symbol("alpha")', # don't split Greek letters/subscripts
|
|
'x_2': 'Symbol("x_2")',
|
|
'sin^2 x**2': 'sin(x**2)**2', # function raised to a power
|
|
'sin**3(x)': 'sin(x)**3',
|
|
'(factorial)': 'factorial',
|
|
'tan 3x': 'tan(3*x)',
|
|
'sin^2(3*E^(x))': 'sin(3*E**(x))**2',
|
|
'sin**2(E^(3x))': 'sin(E**(3*x))**2',
|
|
'sin^2 (3x*E^(x))': 'sin(3*x*E^x)**2',
|
|
'pi sin x': 'pi*sin(x)',
|
|
}
|
|
transformations = standard_transformations + (convert_xor,)
|
|
transformations2 = transformations + (implicit_multiplication_application,)
|
|
for case in cases:
|
|
implicit = parse_expr(case, transformations=transformations2)
|
|
normal = parse_expr(cases[case], transformations=transformations)
|
|
assert(implicit == normal)
|
|
|
|
|
|
def test_no_methods_implicit_multiplication():
|
|
# Issue 21020
|
|
u = sympy.Symbol('u')
|
|
transformations = standard_transformations + \
|
|
(implicit_multiplication,)
|
|
expr = parse_expr('x.is_polynomial(x)', transformations=transformations)
|
|
assert expr == True
|
|
expr = parse_expr('(exp(x) / (1 + exp(2x))).subs(exp(x), u)',
|
|
transformations=transformations)
|
|
assert expr == u/(u**2 + 1)
|