def test_expm1_opt(): x = Symbol('x') expr1 = exp(x) - 1 opt1 = optimize(expr1, [expm1_opt]) assert expm1(x) - opt1 == 0 assert opt1.rewrite(exp) == expr1 expr2 = 3*exp(x) - 3 opt2 = optimize(expr2, [expm1_opt]) assert 3*expm1(x) == opt2 assert opt2.rewrite(exp) == expr2 expr3 = 3*exp(x) - 5 assert expr3 == optimize(expr3, [expm1_opt]) expr4 = 3*exp(x) + log(x) - 3 opt4 = optimize(expr4, [expm1_opt]) assert 3*expm1(x) + log(x) == opt4 assert opt4.rewrite(exp) == expr4 expr5 = 3*exp(2*x) - 3 opt5 = optimize(expr5, [expm1_opt]) assert 3*expm1(2*x) == opt5 assert opt5.rewrite(exp) == expr5
def test_SeriesApprox_trivial(): x, z = symbols('x z') for factor in [1, exp(z)]: x = symbols('x') expr1 = exp(x) * factor bnds1 = {x: (-1, 1)} series_approx_50 = SeriesApprox(bounds=bnds1, reltol=0.50) series_approx_10 = SeriesApprox(bounds=bnds1, reltol=0.10) series_approx_05 = SeriesApprox(bounds=bnds1, reltol=0.05) c = (bnds1[x][1] + bnds1[x][0]) / 2 # 0.0 f0 = math.exp(c) # 1.0 ref_50 = f0 + x + x**2 / 2 ref_10 = f0 + x + x**2 / 2 + x**3 / 6 ref_05 = f0 + x + x**2 / 2 + x**3 / 6 + x**4 / 24 res_50 = optimize(expr1, [series_approx_50]) res_10 = optimize(expr1, [series_approx_10]) res_05 = optimize(expr1, [series_approx_05]) assert (res_50 / factor - ref_50).simplify() == 0 assert (res_10 / factor - ref_10).simplify() == 0 assert (res_05 / factor - ref_05).simplify() == 0 max_ord3 = SeriesApprox(bounds=bnds1, reltol=0.05, max_order=3) assert optimize(expr1, [max_ord3]) == expr1
def test_expm1_opt(): x = Symbol('x') expr1 = exp(x) - 1 opt1 = optimize(expr1, [expm1_opt]) assert expm1(x) - opt1 == 0 assert opt1.rewrite(exp) == expr1 expr2 = 3 * exp(x) - 3 opt2 = optimize(expr2, [expm1_opt]) assert 3 * expm1(x) == opt2 assert opt2.rewrite(exp) == expr2 expr3 = 3 * exp(x) - 5 assert expr3 == optimize(expr3, [expm1_opt]) expr4 = 3 * exp(x) + log(x) - 3 opt4 = optimize(expr4, [expm1_opt]) assert 3 * expm1(x) + log(x) == opt4 assert opt4.rewrite(exp) == expr4 expr5 = 3 * exp(2 * x) - 3 opt5 = optimize(expr5, [expm1_opt]) assert 3 * expm1(2 * x) == opt5 assert opt5.rewrite(exp) == expr5
def test_SeriesApprox_trivial(): x, z = symbols('x z') for factor in [1, exp(z)]: x = symbols('x') expr1 = exp(x)*factor bnds1 = {x: (-1, 1)} series_approx_50 = SeriesApprox(bounds=bnds1, reltol=0.50) series_approx_10 = SeriesApprox(bounds=bnds1, reltol=0.10) series_approx_05 = SeriesApprox(bounds=bnds1, reltol=0.05) c = (bnds1[x][1] + bnds1[x][0])/2 # 0.0 f0 = math.exp(c) # 1.0 ref_50 = f0 + x + x**2/2 ref_10 = f0 + x + x**2/2 + x**3/6 ref_05 = f0 + x + x**2/2 + x**3/6 + x**4/24 res_50 = optimize(expr1, [series_approx_50]) res_10 = optimize(expr1, [series_approx_10]) res_05 = optimize(expr1, [series_approx_05]) assert (res_50/factor - ref_50).simplify() == 0 assert (res_10/factor - ref_10).simplify() == 0 assert (res_05/factor - ref_05).simplify() == 0 max_ord3 = SeriesApprox(bounds=bnds1, reltol=0.05, max_order=3) assert optimize(expr1, [max_ord3]) == expr1
def test_matsolve(): n = Symbol('n', integer=True) A = MatrixSymbol('A', n, n) x = MatrixSymbol('x', n, 1) with assuming(Q.fullrank(A)): assert optimize(A**(-1) * x, [matinv_opt]) == MatrixSolve(A, x) assert optimize(A**(-1) * x + x, [matinv_opt]) == MatrixSolve(A, x) + x
def test_exp2_opt(): x = Symbol('x') expr1 = 1 + 2**x opt1 = optimize(expr1, [exp2_opt]) assert opt1 == 1 + exp2(x) assert opt1.rewrite(Pow) == expr1 expr2 = 1 + 3**x assert expr2 == optimize(expr2, [exp2_opt])
def test_SumApprox_monotone_terms(): x, y, z = symbols('x y z') expr1 = exp(z)*(x**2 + y**2 + 1) bnds1 = {x: (0, 1e-3), y: (100, 1000)} sum_approx_m2 = SumApprox(bounds=bnds1, reltol=1e-2) sum_approx_m5 = SumApprox(bounds=bnds1, reltol=1e-5) sum_approx_m11 = SumApprox(bounds=bnds1, reltol=1e-11) assert (optimize(expr1, [sum_approx_m2])/exp(z) - (y**2)).simplify() == 0 assert (optimize(expr1, [sum_approx_m5])/exp(z) - (y**2 + 1)).simplify() == 0 assert (optimize(expr1, [sum_approx_m11])/exp(z) - (y**2 + 1 + x**2)).simplify() == 0
def test_create_expand_pow_optimization(): my_opt = create_expand_pow_optimization(4) x = Symbol('x') assert ccode(optimize(x**4, [my_opt])) == 'x*x*x*x' x5x4 = x**5 + x**4 assert ccode(optimize(x5x4, [my_opt])) == 'pow(x, 5) + x*x*x*x' sin4x = sin(x)**4 assert ccode(optimize(sin4x, [my_opt])) == 'pow(sin(x), 4)'
def test_SumApprox_monotone_terms(): x, y, z = symbols('x y z') expr1 = exp(z) * (x**2 + y**2 + 1) bnds1 = {x: (0, 1e-3), y: (100, 1000)} sum_approx_m2 = SumApprox(bounds=bnds1, reltol=1e-2) sum_approx_m5 = SumApprox(bounds=bnds1, reltol=1e-5) sum_approx_m11 = SumApprox(bounds=bnds1, reltol=1e-11) assert (optimize(expr1, [sum_approx_m2]) / exp(z) - (y**2)).simplify() == 0 assert (optimize(expr1, [sum_approx_m5]) / exp(z) - (y**2 + 1)).simplify() == 0 assert (optimize(expr1, [sum_approx_m11]) / exp(z) - (y**2 + 1 + x**2)).simplify() == 0
def test_create_expand_pow_optimization(): my_opt = create_expand_pow_optimization(4) x = Symbol('x') assert ccode(optimize(x**4, [my_opt])) == 'x*x*x*x' x5x4 = x**5 + x**4 assert ccode(optimize(x5x4, [my_opt])) == 'pow(x, 5) + x*x*x*x' sin4x = sin(x)**4 assert ccode(optimize(sin4x, [my_opt])) == 'pow(sin(x), 4)' assert ccode(optimize((x**(-4)), [my_opt])) == 'pow(x, -4)'
def test_logaddexp_opt(): x, y = map(Symbol, 'x y'.split()) expr1 = log(exp(x) + exp(y)) opt1 = optimize(expr1, [logaddexp_opt]) assert logaddexp(x, y) - opt1 == 0 assert logaddexp(y, x) - opt1 == 0 assert opt1.rewrite(log) == expr1
def test_logaddexp2_opt(): x, y = map(Symbol, 'x y'.split()) expr1 = log(2**x + 2**y) / log(2) opt1 = optimize(expr1, [logaddexp2_opt]) assert logaddexp2(x, y) - opt1 == 0 assert logaddexp2(y, x) - opt1 == 0 assert opt1.rewrite(log) == expr1
def test_create_expand_pow_optimization(): cc = lambda x: ccode( optimize(x, [create_expand_pow_optimization(4)])) x = Symbol('x') assert cc(x**4) == 'x*x*x*x' assert cc(x**4 + x**2) == 'x*x + x*x*x*x' assert cc(x**5 + x**4) == 'pow(x, 5) + x*x*x*x' assert cc(sin(x)**4) == 'pow(sin(x), 4)' # gh issue 15335 assert cc(x**(-4)) == '1.0/(x*x*x*x)' assert cc(x**(-5)) == 'pow(x, -5)' assert cc(-x**4) == '-x*x*x*x' assert cc(x**4 - x**2) == '-x*x + x*x*x*x' i = Symbol('i', integer=True) assert cc(x**i - x**2) == 'pow(x, i) - x*x' # gh issue 20753 cc2 = lambda x: ccode(optimize(x, [create_expand_pow_optimization( 4, base_req=lambda b: b.is_Function)])) assert cc2(x**3 + sin(x)**3) == "pow(x, 3) + sin(x)*sin(x)*sin(x)"
def test_log1p_opt(): x = Symbol('x') expr1 = log(x + 1) opt1 = optimize(expr1, [log1p_opt]) assert log1p(x) - opt1 == 0 assert opt1.rewrite(log) == expr1 expr2 = log(3 * x + 3) opt2 = optimize(expr2, [log1p_opt]) assert log1p(x) + log(3) == opt2 assert (opt2.rewrite(log) - expr2).simplify() == 0 expr3 = log(2 * x + 1) opt3 = optimize(expr3, [log1p_opt]) assert log1p(2 * x) - opt3 == 0 assert opt3.rewrite(log) == expr3 expr4 = log(x + 3) opt4 = optimize(expr4, [log1p_opt]) assert str(opt4) == 'log(x + 3)'
def test_log1p_opt(): x = Symbol('x') expr1 = log(x + 1) opt1 = optimize(expr1, [log1p_opt]) assert log1p(x) - opt1 == 0 assert opt1.rewrite(log) == expr1 expr2 = log(3*x + 3) opt2 = optimize(expr2, [log1p_opt]) assert log1p(x) + log(3) == opt2 assert (opt2.rewrite(log) - expr2).simplify() == 0 expr3 = log(2*x + 1) opt3 = optimize(expr3, [log1p_opt]) assert log1p(2*x) - opt3 == 0 assert opt3.rewrite(log) == expr3 expr4 = log(x+3) opt4 = optimize(expr4, [log1p_opt]) assert str(opt4) == 'log(x + 3)'
def test_log2_opt(): x = Symbol('x') expr1 = 7 * log(3 * x + 5) / (log(2)) opt1 = optimize(expr1, [log2_opt]) assert opt1 == 7 * log2(3 * x + 5) assert opt1.rewrite(log) == expr1 expr2 = 3 * log(5 * x + 7) / (13 * log(2)) opt2 = optimize(expr2, [log2_opt]) assert opt2 == 3 * log2(5 * x + 7) / 13 assert opt2.rewrite(log) == expr2 expr3 = log(x) / log(2) opt3 = optimize(expr3, [log2_opt]) assert opt3 == log2(x) assert opt3.rewrite(log) == expr3 expr4 = log(x) / log(2) + log(x + 1) opt4 = optimize(expr4, [log2_opt]) assert opt4 == log2(x) + log(2) * log2(x + 1) assert opt4.rewrite(log) == expr4 expr5 = log(17) opt5 = optimize(expr5, [log2_opt]) assert opt5 == expr5 expr6 = log(x + 3) / log(2) opt6 = optimize(expr6, [log2_opt]) assert str(opt6) == 'log2(x + 3)' assert opt6.rewrite(log) == expr6
def test_log2_opt(): x = Symbol('x') expr1 = 7*log(3*x + 5)/(log(2)) opt1 = optimize(expr1, [log2_opt]) assert opt1 == 7*log2(3*x + 5) assert opt1.rewrite(log) == expr1 expr2 = 3*log(5*x + 7)/(13*log(2)) opt2 = optimize(expr2, [log2_opt]) assert opt2 == 3*log2(5*x + 7)/13 assert opt2.rewrite(log) == expr2 expr3 = log(x)/log(2) opt3 = optimize(expr3, [log2_opt]) assert opt3 == log2(x) assert opt3.rewrite(log) == expr3 expr4 = log(x)/log(2) + log(x+1) opt4 = optimize(expr4, [log2_opt]) assert opt4 == log2(x) + log(2)*log2(x+1) assert opt4.rewrite(log) == expr4 expr5 = log(17) opt5 = optimize(expr5, [log2_opt]) assert opt5 == expr5 expr6 = log(x + 3)/log(2) opt6 = optimize(expr6, [log2_opt]) assert str(opt6) == 'log2(x + 3)' assert opt6.rewrite(log) == expr6
def test_compiled_ccode_with_rewriting(): if not cython: skip("cython not installed.") if not has_c(): skip("No C compiler found.") x = Symbol('x') about_two = 2**(58 / S(117)) * 3**(97 / S(117)) * 5**(4 / S(39)) * 7**( 92 / S(117)) / S(30) * pi # about_two: 1.999999999999581826 unchanged = 2 * exp(x) - about_two xval = S(10)**-11 ref = unchanged.subs(x, xval).n(19) # 2.0418173913673213e-11 rewritten = optimize(2 * exp(x) - about_two, [expm1_opt]) # Unfortunately, we need to call ``.n()`` on our expressions before we hand them # to ``ccode``, and we need to request a large number of significant digits. # In this test, results converged for double precision when the following number # of significant digits were chosen: NUMBER_OF_DIGITS = 25 # TODO: this should ideally be automatically handled. func_c = ''' #include <math.h> double func_unchanged(double x) { return %(unchanged)s; } double func_rewritten(double x) { return %(rewritten)s; } ''' % dict(unchanged=ccode(unchanged.n(NUMBER_OF_DIGITS)), rewritten=ccode(rewritten.n(NUMBER_OF_DIGITS))) func_pyx = ''' #cython: language_level=3 cdef extern double func_unchanged(double) cdef extern double func_rewritten(double) def py_unchanged(x): return func_unchanged(x) def py_rewritten(x): return func_rewritten(x) ''' with tempfile.TemporaryDirectory() as folder: mod, info = compile_link_import_strings([('func.c', func_c), ('_func.pyx', func_pyx)], build_dir=folder, compile_kwargs=dict(std='c99')) err_rewritten = abs(mod.py_rewritten(1e-11) - ref) err_unchanged = abs(mod.py_unchanged(1e-11) - ref) assert 1e-27 < err_rewritten < 1e-25 # highly accurate. assert 1e-19 < err_unchanged < 1e-16 # quite poor.
def test_optims_c99(): x = Symbol('x') expr1 = 2**x + log(x) / log(2) + log(x + 1) + exp(x) - 1 opt1 = optimize(expr1, optims_c99).simplify() assert opt1 == exp2(x) + log2(x) + log1p(x) + expm1(x) assert opt1.rewrite(exp).rewrite(log).rewrite(Pow) == expr1 expr2 = log(x) / log(2) + log(x + 1) opt2 = optimize(expr2, optims_c99) assert opt2 == log2(x) + log1p(x) assert opt2.rewrite(log) == expr2 expr3 = log(x) / log(2) + log(17 * x + 17) opt3 = optimize(expr3, optims_c99) delta3 = opt3 - (log2(x) + log(17) + log1p(x)) assert delta3 == 0 assert (opt3.rewrite(log) - expr3).simplify() == 0 expr4 = 2**x + 3 * log(5 * x + 7) / (13 * log(2)) + 11 * exp(x) - 11 + log( 17 * x + 17) opt4 = optimize(expr4, optims_c99).simplify() delta4 = opt4 - (exp2(x) + 3 * log2(5 * x + 7) / 13 + 11 * expm1(x) + log(17) + log1p(x)) assert delta4 == 0 assert (opt4.rewrite(exp).rewrite(log).rewrite(Pow) - expr4).simplify() == 0 expr5 = 3 * exp(2 * x) - 3 opt5 = optimize(expr5, optims_c99) delta5 = opt5 - 3 * expm1(2 * x) assert delta5 == 0 assert opt5.rewrite(exp) == expr5 expr6 = exp(2 * x) - 3 opt6 = optimize(expr6, optims_c99) delta6 = opt6 - (exp(2 * x) - 3) assert delta6 == 0 expr7 = log(3 * x + 3) opt7 = optimize(expr7, optims_c99) delta7 = opt7 - (log(3) + log1p(x)) assert delta7 == 0 assert (opt7.rewrite(log) - expr7).simplify() == 0 expr8 = log(2 * x + 3) opt8 = optimize(expr8, optims_c99) assert opt8 == expr8
def test_create_expand_pow_optimization(): cc = lambda x: ccode(optimize(x, [create_expand_pow_optimization(4)])) x = Symbol('x') assert cc(x**4) == 'x*x*x*x' assert cc(x**4 + x**2) == 'x*x + x*x*x*x' assert cc(x**5 + x**4) == 'pow(x, 5) + x*x*x*x' assert cc(sin(x)**4) == 'pow(sin(x), 4)' # gh issue 15335 assert cc(x**(-4)) == '1.0/(x*x*x*x)' assert cc(x**(-5)) == 'pow(x, -5)' assert cc(-x**4) == '-x*x*x*x' assert cc(x**4 - x**2) == '-x*x + x*x*x*x' i = Symbol('i', integer=True) assert cc(x**i - x**2) == 'pow(x, i) - x*x'
def test_create_expand_pow_optimization(): cc = lambda x: ccode(optimize(x, [create_expand_pow_optimization(4)])) x = Symbol("x") assert cc(x**4) == "x*x*x*x" assert cc(x**4 + x**2) == "x*x + x*x*x*x" assert cc(x**5 + x**4) == "pow(x, 5) + x*x*x*x" assert cc(sin(x)**4) == "pow(sin(x), 4)" # gh issue 15335 assert cc(x**(-4)) == "1.0/(x*x*x*x)" assert cc(x**(-5)) == "pow(x, -5)" assert cc(-(x**4)) == "-x*x*x*x" assert cc(x**4 - x**2) == "-x*x + x*x*x*x" i = Symbol("i", integer=True) assert cc(x**i - x**2) == "pow(x, i) - x*x"
def optimize_expr_for_c_output(expr): """Returns expression optimised for c++ export with regards to powers and logarithms :param expr: the expression to apply power and log optimisations to. :return: The expression with the optimisations applied. """ optims = tuple() if expr.has(log): optims += (_LOG_OPTIMS) if expr.has(Pow): optims += (_POW_OPT, ) if len(optims) > 0: return optimize(expr, optims) return expr
def ccode(eq) -> str: """Transforms a sympy expression into C99 code. Applies C99 optimizations (`sympy.codegen.rewriting.optims_c99`). Expands `pow(x; 2)` into `x*x` and `pow(x, 3)` into `x*x*x` for performance. Args: eq (sympy expression): expression to convert. Returns: a string representing the C code. """ # If the rhs is a int or float (v = 0.0), cast it to a symbol to avoid numerical errors. if isinstance(eq, (float)): eq = sp.Symbol(str(float(eq))) elif isinstance(eq, (int)): eq = sp.Symbol(str(int(eq))) # Optimize for C99 try: eq = optimize(eq, optims_c99) except: logger = logging.getLogger(__name__) logger.exception(str(eq)) sys.exit(1) # Explicitly expand the use of pow(x, 2) pow2 = ReplaceOptim( lambda p: p.is_Pow and p.exp == 2, lambda p: UnevaluatedExpr(Mul(p.base, p.base, evaluate=False)) ) eq = pow2(eq) # Explicitly expand the use of pow(x, 3) pow3 = ReplaceOptim( lambda p: p.is_Pow and p.exp == 3, lambda p: UnevaluatedExpr(Mul(Mul(p.base, p.base, evaluate=False), p.base, evaluate=False)) ) eq = pow3(eq) # Get the equivalent C code eq = sp.ccode( eq, ) # Remove the extralines of Piecewise return " ".join(eq.replace('\n', ' ').split())
def test_optims_c99(): x = Symbol('x') expr1 = 2**x + log(x)/log(2) + log(x + 1) + exp(x) - 1 opt1 = optimize(expr1, optims_c99).simplify() assert opt1 == exp2(x) + log2(x) + log1p(x) + expm1(x) assert opt1.rewrite(exp).rewrite(log).rewrite(Pow) == expr1 expr2 = log(x)/log(2) + log(x + 1) opt2 = optimize(expr2, optims_c99) assert opt2 == log2(x) + log1p(x) assert opt2.rewrite(log) == expr2 expr3 = log(x)/log(2) + log(17*x + 17) opt3 = optimize(expr3, optims_c99) delta3 = opt3 - (log2(x) + log(17) + log1p(x)) assert delta3 == 0 assert (opt3.rewrite(log) - expr3).simplify() == 0 expr4 = 2**x + 3*log(5*x + 7)/(13*log(2)) + 11*exp(x) - 11 + log(17*x + 17) opt4 = optimize(expr4, optims_c99).simplify() delta4 = opt4 - (exp2(x) + 3*log2(5*x + 7)/13 + 11*expm1(x) + log(17) + log1p(x)) assert delta4 == 0 assert (opt4.rewrite(exp).rewrite(log).rewrite(Pow) - expr4).simplify() == 0 expr5 = 3*exp(2*x) - 3 opt5 = optimize(expr5, optims_c99) delta5 = opt5 - 3*expm1(2*x) assert delta5 == 0 assert opt5.rewrite(exp) == expr5 expr6 = exp(2*x) - 3 opt6 = optimize(expr6, optims_c99) delta6 = opt6 - (exp(2*x) - 3) assert delta6 == 0 expr7 = log(3*x + 3) opt7 = optimize(expr7, optims_c99) delta7 = opt7 - (log(3) + log1p(x)) assert delta7 == 0 assert (opt7.rewrite(log) - expr7).simplify() == 0 expr8 = log(2*x + 3) opt8 = optimize(expr8, optims_c99) assert opt8 == expr8
def test_cosm1_opt(): x = Symbol('x') expr1 = cos(x) - 1 opt1 = optimize(expr1, [cosm1_opt]) assert cosm1(x) - opt1 == 0 assert opt1.rewrite(cos) == expr1 expr2 = 3 * cos(x) - 3 opt2 = optimize(expr2, [cosm1_opt]) assert 3 * cosm1(x) == opt2 assert opt2.rewrite(cos) == expr2 expr3 = 3 * cos(x) - 5 opt3 = optimize(expr3, [cosm1_opt]) assert 3 * cosm1(x) - 2 == opt3 assert opt3.rewrite(cos) == expr3 cosm1_opt_non_opportunistic = FuncMinusOneOptim(cos, cosm1, opportunistic=False) assert expr3 == optimize(expr3, [cosm1_opt_non_opportunistic]) assert opt1 == optimize(expr1, [cosm1_opt_non_opportunistic]) assert opt2 == optimize(expr2, [cosm1_opt_non_opportunistic]) expr4 = 3 * cos(x) + log(x) - 3 opt4 = optimize(expr4, [cosm1_opt]) assert 3 * cosm1(x) + log(x) == opt4 assert opt4.rewrite(cos) == expr4 expr5 = 3 * cos(2 * x) - 3 opt5 = optimize(expr5, [cosm1_opt]) assert 3 * cosm1(2 * x) == opt5 assert opt5.rewrite(cos) == expr5 expr6 = 2 - 2 * cos(x) opt6 = optimize(expr6, [cosm1_opt]) assert -2 * cosm1(x) == opt6 assert opt6.rewrite(cos) == expr6
def generate(export): # Generate code from exported routines. generator = cgen.CCodeGen(cse=True) routines = [ generator.routine(name, copt.optimize(sym.simplify(expr), copt.optims_c99), None, None) for name, expr in export ] codes = [ generator.write((routine, ), "", header=False, empty=True) for routine in routines ] codes = [code for (_, code), (_, _) in codes] # Sanitize generated code. for i in range(len(codes)): # Split code into lines. Remove include ones. lines = codes[i].split('\n') lines = lines[3:] # Reindent from 3 spaces to 4 spaces :| lines = [line.replace(' ', ' ') for line in lines] # Convert input and output argument variables to Eigen types. for var in routines[i].arguments: lines = convert_var_to_eigen(var, lines, var in routines[i].result_variables) # Rename result variable to something legible. result = routines[i].result_variables[-1] name = str(result.name) if result.dimensions is not None else str( routines[i].name) + '_result' lines = [line.replace(name, 'out') for line in lines] # Rejoin code. codes[i] = '\n'.join(lines) # Done! return codes
def apply_sympy_optimisations(assignments): """ Evaluates constant expressions (e.g. :math:`\\sqrt{3}` will be replaced by its floating point representation) and applies the default sympy optimisations. See sympy.codegen.rewriting """ # Evaluates all constant terms evaluate_constant_terms = ReplaceOptim( lambda e: hasattr(e, 'is_constant') and e.is_constant and not e. is_integer, lambda p: p.evalf(17)) sympy_optimisations = [evaluate_constant_terms] + list(optims_c99) assignments = [ Assignment(a.lhs, optimize(a.rhs, sympy_optimisations)) if hasattr( a, 'lhs') else a for a in assignments ] assignments_nodes = [a.atoms(SympyAssignment) for a in assignments] for a in chain.from_iterable(assignments_nodes): a.optimize(sympy_optimisations) return assignments
def optimize(self, optimizations): try: from sympy.codegen.rewriting import optimize self.rhs = optimize(self.rhs, optimizations) except Exception: pass
def check(d): for k, v in d.items(): assert optimize(k, optims_numpy) == v
def test_SumApprox_trivial(): x = symbols('x') expr1 = 1 + x sum_approx = SumApprox(bounds={x: (-1e-20, 1e-20)}, reltol=1e-16) apx1 = optimize(expr1, [sum_approx]) assert apx1 - 1 == 0
def test_cosm1_two_cos_terms(): x, y = map(Symbol, 'x y'.split()) expr1 = cos(x) + cos(y) - 2 opt1 = optimize(expr1, [cosm1_opt]) assert opt1 == cosm1(x) + cosm1(y)
def test_expm1_opt(): x = Symbol('x') expr1 = exp(x) - 1 opt1 = optimize(expr1, [expm1_opt]) assert expm1(x) - opt1 == 0 assert opt1.rewrite(exp) == expr1 expr2 = 3 * exp(x) - 3 opt2 = optimize(expr2, [expm1_opt]) assert 3 * expm1(x) == opt2 assert opt2.rewrite(exp) == expr2 expr3 = 3 * exp(x) - 5 opt3 = optimize(expr3, [expm1_opt]) assert 3 * expm1(x) - 2 == opt3 assert opt3.rewrite(exp) == expr3 expm1_opt_non_opportunistic = FuncMinusOneOptim(exp, expm1, opportunistic=False) assert expr3 == optimize(expr3, [expm1_opt_non_opportunistic]) assert opt1 == optimize(expr1, [expm1_opt_non_opportunistic]) assert opt2 == optimize(expr2, [expm1_opt_non_opportunistic]) expr4 = 3 * exp(x) + log(x) - 3 opt4 = optimize(expr4, [expm1_opt]) assert 3 * expm1(x) + log(x) == opt4 assert opt4.rewrite(exp) == expr4 expr5 = 3 * exp(2 * x) - 3 opt5 = optimize(expr5, [expm1_opt]) assert 3 * expm1(2 * x) == opt5 assert opt5.rewrite(exp) == expr5 expr6 = (2 * exp(x) + 1) / (exp(x) + 1) + 1 opt6 = optimize(expr6, [expm1_opt]) assert opt6.count_ops() <= expr6.count_ops() def ev(e): return e.subs(x, 3).evalf() assert abs(ev(expr6) - ev(opt6)) < 1e-15 y = Symbol('y') expr7 = (2 * exp(x) - 1) / (1 - exp(y)) - 1 / (1 - exp(y)) opt7 = optimize(expr7, [expm1_opt]) assert -2 * expm1(x) / expm1(y) == opt7 assert (opt7.rewrite(exp) - expr7).factor() == 0 expr8 = (1 + exp(x))**2 - 4 opt8 = optimize(expr8, [expm1_opt]) tgt8a = (exp(x) + 3) * expm1(x) tgt8b = 2 * expm1(x) + expm1(2 * x) # Both tgt8a & tgt8b seem to give full precision (~16 digits for double) # for x=1e-7 (compare with expr8 which only achieves ~8 significant digits). # If we can show that either tgt8a or tgt8b is preferable, we can # change this test to ensure the preferable version is returned. assert (tgt8a - tgt8b).rewrite(exp).factor() == 0 assert opt8 in (tgt8a, tgt8b) assert (opt8.rewrite(exp) - expr8).factor() == 0 expr9 = sin(expr8) opt9 = optimize(expr9, [expm1_opt]) tgt9a = sin(tgt8a) tgt9b = sin(tgt8b) assert opt9 in (tgt9a, tgt9b) assert (opt9.rewrite(exp) - expr9.rewrite(exp)).factor().is_zero
def test_expm1_cosm1_mixed(): x = Symbol('x') expr1 = exp(x) + cos(x) - 2 opt1 = optimize(expr1, [expm1_opt, cosm1_opt]) assert opt1 == cosm1(x) + expm1(x)
def check(d): for k, v in d.items(): assert optimize(k, sinc_opts) == v
def test_expm1_two_exp_terms(): x, y = map(Symbol, 'x y'.split()) expr1 = exp(x) + exp(y) - 2 opt1 = optimize(expr1, [expm1_opt]) assert opt1 == expm1(x) + expm1(y)
def test_expm1_cosm1_mixed(): x = Symbol('x') expr1 = exp(x) + cos(x) - 2 opt1 = optimize(expr1, [expm1_opt, cosm1_opt]) # need a combined opt pass? assert opt1 == cosm1(x) + expm1(x)