sympy CSE: избегать пау / пауф

Когда Sympy генерирует код на C, есть ли способ обеспечить оптимизацию CSE для вхождений pow (или powf) в выражении?

Например, этот фрагмент кода

c, s = symbols('c s')
myexpr = c**6/1800 - c**5/100 - 0.00833333333333333*c**4*s**2 + 19*c**4/200 + 0.1*c**3*s**2 - 9*c**3/20 + c**2*s**4/120 - 0.57*c**2*s**2 + 43*c**2/40 - c*s**4/20 + 1.35*c*s**2 + 23*c/50 - 0.000555555555555556*s**6 + 19*s**4/200 - 1.075*s**2 - 2107/1800
import sympy
from sympy.codegen.ast import real, float64
sub_exprs,final_expr = sympy.cse([myexpr])
for var,expr in sub_exprs : print "const real", printing.ccode(expr, standard='C99', assign_to=var, type_aliases={real: float64})
print "return ",printing.ccode(final_expr[0], standard='C99', type_aliases={real: float64}),";"

производит следующий неутешительный вывод:

const real x0 = pow(c, 2); 
const real x1 = pow(c, 3); 
const real x2 = pow(c, 4); 
const real x3 = pow(s, 2); 
const real x4 = pow(s, 4); 

return (1.0/1800.0)*pow(c, 6) - 1.0/100.0*pow(c, 5) + 1.3500000000000001*c*x3 - 1.0/20.0*c*x4 + (23.0/50.0)*c - 0.00055555555555555599*pow(s, 6) - 0.56999999999999995*x0*x3 + (1.0/120.0)*x0*x4 + (43.0/40.0)*x0 + 0.10000000000000001*x1*x3 - 9.0/20.0*x1 - 0.0083333333333333297*x2*x3 + (19.0/200.0)*x2 - 1.075*x3 + (19.0/200.0)*x4 - 2107.0/1800.0 ;

Оптимизация Pow была полностью проигнорирована.

Какой обходной путь для этого?

Примечание: я видел, что эта проблема частично упоминается здесь: "Во многих случаях принтеры кода не печатают оптимальный код. Примером этого является мощность в C. x**2 печатает как pow(x, 2) вместо x * х. Другие оптимизации (например, математические упрощения) должны произойти до того, как появятся принтеры кода."

1 ответ

Процедура CSE в sympy не идеальна (улучшенная CSE указана как область для улучшения), например:

>>> sympy.cse([x**4, x**3*y])
([], [x**4, x**3*y])

расширяющийся pow в принтере или до того, как принтер обсуждался некоторое время, теперь есть оптимизация create_expand_pow, которая может помочь некоторым:

>>> expand_opt = create_expand_pow_optimization(3)
>>> expand_opt(x**5 + x**3)
x**5 + x*x*x

Однако обратите внимание, что большинство компиляторов уже сгенерируют оптимальную сборку (независимо от CSE в исходном коде), если вы передадите им правильные флаги оптимизации.

Другие вопросы по тегам