【问题标题】:Symbolic simplification to least number of plus and multiply operations符号简化为最少数量的加法和乘法运算
【发布时间】:2017-02-22 14:18:32
【问题描述】:

最近我不得不使用具有很多长符号表达式的算法,例如这个

upperside = (    e * e * n * p * tn * tn + 
             2 * e * e * n * p * tn * tp +  
                 e * e * n * p * tp * tp + 
             2 * e * n * n * p * te * tn + 
             2 * e * n * n * p * te * tp +
                 N * e * n * n * tp * tp + 
             2 * e * n * p * p * te * tn +
             2 * e * n * p * p * te * tp - 
             2 * N * e * n * p * tn * tp + 
                 N * e * p * p * tn * tn +
                 n * n * n * p * te * te + 
             2 * n * n * p * p * te * te + 
                 n * p * p * p * te * te)

改版

upperside = (        e * e * n         * p                  * tn * tn           + 
             2     * e * e * n         * p                  * tn      * tp      +  
                     e * e * n         * p                            * tp * tp + 
             2     * e     * n * n     * p         * te     * tn                + 
             2     * e     * n * n     * p         * te               * tp      +
                 N * e     * n * n                                    * tp * tp + 
             2     * e     * n         * p * p     * te     * tn                +
             2     * e     * n         * p * p     * te               * tp      - 
             2 * N * e     * n         * p                  * tn      * tp      + 
                 N * e                 * p * p              * tn * tn           +
                             n * n * n * p         * te * te                    + 
             2             * n * n     * p * p     * te * te                    + 
                             n         * p * p * p * te * te)

这些表达式是从 MATLAB 符号例程经过简化后推导出来的。很明显,在这种情况下,不可能通过例如合并因子来简化代数表达式。但是,似乎很有可能简化这个表达式,从而大大减少实际操作数。不幸的是,我在 MATLAB 或 Python 中找不到这样的选项。

感谢任何帮助。

编辑 目标是最小化 CPU 需要为此类表达式执行的操作。由于操作只涉及加法和乘法,我希望像 (e+tn)*(te+tp)+n+.... 我试图分解表达式,但不幸的是表达式不可分解。

【问题讨论】:

  • 那么输出会是什么?
  • 我希望乘积和加法的组合(例如,(e+n)(te+tp)+te+n...)。目标是找到一种方法来计算上述数量,从而尽可能少地涉及 CPU 操作
  • 您删除了Python 标签,但您的问题中仍然提到了Python。哪一个是错误的或不相关的?
  • 在 Python 中 - Sympy?例如this
  • @Sardar_Usama 我试图移动标签,以便首先出现符号数学。但不知为何我把它搞砸了……

标签: python matlab symbolic-math


【解决方案1】:

如果有任何 python 包可以提供帮助,它可能是Sympy

from sympy import init_printing, symbols, simplify, collect, factor

e,n,p,tn,te,tp,N = symbols("e,n,p,tn,te,tp,N")

upperside = (e * e * n * p * tn * tn + 
         2 * e * e * n * p * tn * tp +
             e * e * n * p * tp * tp + 
         2 * e * n * n * p * te * tn + 
         2 * e * n * n * p * te * tp +
             N * e * n * n * tp * tp + 
         2 * e * n * p * p * te * tn +
         2 * e * n * p * p * te * tp - 
         2 * N * e * n * p * tn * tp + 
             N * e * p * p * tn * tn +
             n * n * n * p * te * te + 
         2 * n * n * p * p * te * te + 
             n * p * p * p * te * te)

print collect(upperside, e*n)

它输出:

N*e*p**2*tn**2 + 
e**2*n*(p*tn**2 + 2*p*tn*tp + p*tp**2) + 
e*n**2*(N*tp**2 + 2*p*te*tn + 2*p*te*tp) + 
e*n*(-2*N*p*tn*tp + 2*p**2*te*tn + 2*p**2*te*tp) + 
n**3*p*te**2 + 
2*n**2*p**2*te**2 + 
n*p**3*te**2

page 中描述的所有方法中,collect 看起来最有前途。

这是一种快速而肮脏的方法来迭代所有符号组合并显示找到的最短表达式:

from sympy import init_printing, symbols, collect, pprint
import itertools

init_printing()

e,n,p,tn,te,tp,big_n = symbols("e,n,p,tn,te,tp,big_n")

upperside = (e * e * n * p * tn * tn + 2 * e * e * n * p * tn * tp +
                 e * e * n * p * tp * tp + 2 * e * n * n * p * te * tn + 2 * e * n * n * p * te * tp +
                 big_n * e * n * n * tp * tp + 2 * e * n * p * p * te * tn +
                 2 * e * n * p * p * te * tp - 2 * big_n * e * n * p * tn * tp + big_n * e * p * p * tn * tn +
                 n * n * n * p * te * te + 2 * n * n * p * p * te * te + n * p * p * p * te * te)

my_symbols = [e, n, p, tn, te, tp, big_n]

min_length = float('inf')

for i in range(len(my_symbols)):
  for symbol_subsets in itertools.combinations(my_symbols, i+1):
      collect_by = '*'.join(str(symbol) for symbol in symbol_subsets)
      expression = collect(upperside, collect_by)
      length = len(str(expression))
      if length < min_length:
          min_length = length
          print "With '%s' :" % collect_by
          pprint(expression)
          print

它输出:

With 'e' :
e**2*(n*p*tn**2 + 2*n*p*tn*tp + n*p*tp**2) + e*(big_n*n**2*tp**2 - 2*big_n*n*p*tn*tp + big_n*p**2*tn**2 + 2*n**2*p*te*tn + 2*n**2*p*te*tp + 2*n*p**2*te*tn + 2*n*p**2*te*tp) + n**3*p*te**2 + 2*n**2*p**2*te**2 + n*p**3*te**2

With 'n' :
big_n*e*p**2*tn**2 + n**3*p*te**2 + n**2*(big_n*e*tp**2 + 2*e*p*te*tn + 2*e*p*te*tp + 2*p**2*te**2) + n*(-2*big_n*e*p*tn*tp + e**2*p*tn**2 + 2*e**2*p*tn*tp + e**2*p*tp**2 + 2*e*p**2*te*tn + 2*e*p**2*te*tp + p**3*te**2)

With 'e*n' :
big_n*e*p**2*tn**2 + e**2*n*(p*tn**2 + 2*p*tn*tp + p*tp**2) + e*n**2*(big_n*tp**2 + 2*p*te*tn + 2*p*te*tp) + e*n*(-2*big_n*p*tn*tp + 2*p**2*te*tn + 2*p**2*te*tp) + n**3*p*te**2 + 2*n**2*p**2*te**2 + n*p**3*te**2

With 'e*n*p' :
big_n*e*n**2*tp**2 - 2*big_n*e*n*p*tn*tp + big_n*e*p**2*tn**2 + e**2*n*p*(tn**2 + 2*tn*tp + tp**2) + e*n**2*p*(2*te*tn + 2*te*tp) + e*n*p**2*(2*te*tn + 2*te*tp) + n**3*p*te**2 + 2*n**2*p**2*te**2 + n*p**3*te**2

【讨论】:

    【解决方案2】:

    通用子表达式消除(或 sympy cse)计算乘积,例如:ee 和 ep 以及加法。这有助于找到一个非常优化的表达式。我已经看到了具有 3 种不同数学方法的巨大表达式,并且计算时间大不相同。使用 cse 后,这 3 种配方的计算时间几乎相同。并且一些大的因素比最快的非优化算法更快。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-07-18
      • 1970-01-01
      • 2015-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多